Patch improving Nyquist input behavior

12 messages Options
Embed this post
Permalink
Al Dimond

Patch improving Nyquist input behavior

Reply Threaded More More options
Print post
Permalink
Following this discussion on the audacity-nyquist list:

http://n2.nabble.com/Inputting-exact-values-into-Audacity-Nyquist-
effects-td3850278.html#a3850278

I've developed a patch improving the behavior of dialog boxes for
Nyquist plugin inputs.  This solves the bug "P3: Nyquist
implementation: Values appearing in effects text boxes are not always
the hard-coded/previously entered values", and also makes it easier
for users to enter values into the text boxes at higher precision than
what's usually displayed (it used to be that they could not touch
other sliders without having their custom values rounded to the
nearest slider "tick").

 - Al

[awd_nyquist_exact_inputs_3.patch]

Index: src/effects/nyquist/Nyquist.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/effects/nyquist/Nyquist.cpp,v
retrieving revision 1.84
diff -u -r1.84 Nyquist.cpp
--- src/effects/nyquist/Nyquist.cpp 18 Sep 2009 08:18:49 -0000 1.84
+++ src/effects/nyquist/Nyquist.cpp 22 Oct 2009 00:48:37 -0000
@@ -1049,22 +1049,48 @@
       wxASSERT(slider && text);
       
       int val = slider->GetValue();
-      ctrl->val = (val / (double)ctrl->ticks)*
+
+      double newVal = (val / (double)ctrl->ticks)*
          (ctrl->high - ctrl->low) + ctrl->low;
-      
+
+      // Determine precision for displayed number
+      int precision = ctrl->high - ctrl->low < 1 ? 3 :
+                      ctrl->high - ctrl->low < 10 ? 2 :
+                      ctrl->high - ctrl->low < 100 ? 1 :
+                      0;
+
+      // If the value is at least one tick different from the current value
+      // change it (this prevents changes from manually entered values unless
+      // the slider actually moved)
+      if (fabs(newVal - ctrl->val) >= (1 / (double)ctrl->ticks) *
+                                      (ctrl->high - ctrl->low) &&
+          fabs(newVal - ctrl->val) >= pow(0.1, precision) / 2 )
+      {
+         // First round to the appropriate precision
+         newVal *= pow(10, precision);
+         newVal = floor(newVal + 0.5);
+         newVal /= pow(10, precision);
+
+         ctrl->val = newVal;
+      }
+
       wxString valStr;
       if (ctrl->type == NYQ_CTRL_REAL) {
-         if (ctrl->high - ctrl->low < 1) {
-            valStr = Internat::ToDisplayString(ctrl->val, 3);
-         }
-         else if (ctrl->high - ctrl->low < 10) {
-            valStr = Internat::ToDisplayString(ctrl->val, 2);
-         }
-         else if (ctrl->high - ctrl->low < 100) {
-            valStr = Internat::ToDisplayString(ctrl->val, 1);
-         }
-         else {
-            valStr.Printf(wxT("%d"), (int)floor(ctrl->val + 0.5));
+         // If this is a user-typed value, allow unlimited precision
+         if (ctrl->val != newVal)
+         {
+            valStr = Internat::ToDisplayString(ctrl->val);
+         }
+         else
+         {
+            if (precision == 0)
+            {
+               valStr.Printf(wxT("%d"), (int)floor(ctrl->val + 0.5));
+            }
+            else
+            {
+               valStr = Internat::ToDisplayString(ctrl->val, precision);
+            }
          }
       }
       else if (ctrl->type == NYQ_CTRL_INT) {


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
Stevethefiddle

Re: Patch improving Nyquist input behavior

Reply Threaded More More options
Print post
Permalink

Al Dimond wrote:
Following this discussion on the audacity-nyquist list:

http://n2.nabble.com/Inputting-exact-values-into-Audacity-Nyquist-
effects-td3850278.html#a3850278

I've developed a patch improving the behavior of dialog boxes for
Nyquist plugin inputs.  This solves the bug "P3: Nyquist
implementation: Values appearing in effects text boxes are not always
the hard-coded/previously entered values", and also makes it easier
for users to enter values into the text boxes at higher precision than
what's usually displayed (it used to be that they could not touch
other sliders without having their custom values rounded to the
nearest slider "tick").

 - Al

Index: src/effects/nyquist/Nyquist.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/effects/nyquist/Nyquist.cpp,v
retrieving revision 1.84
diff -u -r1.84 Nyquist.cpp
--- src/effects/nyquist/Nyquist.cpp 18 Sep 2009 08:18:49 -0000 1.84
+++ src/effects/nyquist/Nyquist.cpp 22 Oct 2009 00:48:37 -0000
@@ -1049,22 +1049,48 @@
       wxASSERT(slider && text);
       
       int val = slider->GetValue();
-      ctrl->val = (val / (double)ctrl->ticks)*
+
+      double newVal = (val / (double)ctrl->ticks)*
          (ctrl->high - ctrl->low) + ctrl->low;
-      
+
+      // Determine precision for displayed number
+      int precision = ctrl->high - ctrl->low < 1 ? 3 :
+                      ctrl->high - ctrl->low < 10 ? 2 :
+                      ctrl->high - ctrl->low < 100 ? 1 :
+                      0;
+
+      // If the value is at least one tick different from the current value
+      // change it (this prevents changes from manually entered values unless
+      // the slider actually moved)
+      if (fabs(newVal - ctrl->val) >= (1 / (double)ctrl->ticks) *
+                                      (ctrl->high - ctrl->low) &&
+          fabs(newVal - ctrl->val) >= pow(0.1, precision) / 2 )
+      {
+         // First round to the appropriate precision
+         newVal *= pow(10, precision);
+         newVal = floor(newVal + 0.5);
+         newVal /= pow(10, precision);
+
+         ctrl->val = newVal;
+      }
+
       wxString valStr;
       if (ctrl->type == NYQ_CTRL_REAL) {
-         if (ctrl->high - ctrl->low < 1) {
-            valStr = Internat::ToDisplayString(ctrl->val, 3);
-         }
-         else if (ctrl->high - ctrl->low < 10) {
-            valStr = Internat::ToDisplayString(ctrl->val, 2);
-         }
-         else if (ctrl->high - ctrl->low < 100) {
-            valStr = Internat::ToDisplayString(ctrl->val, 1);
-         }
-         else {
-            valStr.Printf(wxT("%d"), (int)floor(ctrl->val + 0.5));
+         // If this is a user-typed value, allow unlimited precision
+         if (ctrl->val != newVal)
+         {
+            valStr = Internat::ToDisplayString(ctrl->val);
+         }
+         else
+         {
+            if (precision == 0)
+            {
+               valStr.Printf(wxT("%d"), (int)floor(ctrl->val + 0.5));
+            }
+            else
+            {
+               valStr = Internat::ToDisplayString(ctrl->val, precision);
+            }
          }
       }
       else if (ctrl->type == NYQ_CTRL_INT) {
Good to see that the new version of this is now in the Audacity source code.
I've found this limitation of Audacity-Nyquist quite irritating, but this fixes it beautifully.
Thanks
edgar-rft

Audacity Nyquist source code research for writing new documentation

Reply Threaded More More options
Print post
Permalink
Hi Audacity Nyquist list,

Because it's (once again) a month ago, here is a summary of what
happened last:

 > Dave Storer asked:

 > I there a way to carry over any information from one call to the next
 > except by saving the state information in an external file?

 > Leland wrote:

 > There's a global variable called *SCRATCH* that can be used for
 > this purpose. It is not restored between between tracks. A couple
 > of new comment statements were added when I did the upgrade.

 > ;codetype lisp | sal

 > Tells Audacity the syntax to expect and how to pass it on to libnyquist.
 > The default is lisp.  Only one type is allowed.

 > ;debugflags trace | notrace | compiler | nocompiler

 > Trace and notrace simply set Nyquist's "*tracenable*" global. This is
 > similar to clicking the Debug button in the Nyquist prompt, but it
 > allows the plug-in to control it instead.

 > Compiler and nocompiler controls whether the generated Lisp code from
 > the SAL compiler will be sent to stdout or to the output window in the
 > Nyquist Workbench.

-----

Edgar - What I have so far...

Looking at the source code of Audacity 1.3.10-alpha, 2009 Nov 18:

According to "audacity/src/effects/Nyquist.cpp" the following control
lines are currently recognized in Audacity Nyquist plugins:

;version    - the Audacity Plugin version (1, 2, or 3)

// Version 1 only supported the slider widget
// Version 2 added support for string widgets
// Version 3 added support for choice widgets

;name       - the user-defined name of the plugin
;action     - the text in the message box when the effect is applied
;info       - some info text displayed in the plugin window

;control    - a slider widget
;string     - a string input widget
;choice     - a multiple-choice list-box widget

;categories - I have no idea what this is for ???

According to "audacity/src/effects/Nyquist.cpp" the following global
variables are set as a result of parsing the plugin header lines:

*sal-compiler-debug* - set by ";debugflags compiler | nocompiler"
*sal-call-stack*     - always reset to NIL
*tracenable*         - set by ";debugflags trace | notrace"
*breakenable*        - set by the "EffectNyquist::SetCommand" function
// Maybe "EffectNyquist::SetCommand" is called by external modules
// like the Nyquist Workbench?  I have found no other references in
// the Audacity source code.

According to "audacity/lib-src/libnyquist/nyx.c" the following global
variables are set by the Audacity Nyquist interface:

S             (SOUND)  - the Audacity sound object
LEN           (FLONUM) - length of the Audacity selection in samples
*SOUND-SRATE* (FLONUM) - sample frequency of the Audacity track
*WARP*        (LIST)   - the warp transformation environment variable

Variables which get NOT deleted or updated in subsequent invocations
of Nyquist plugins:

*SCRATCH* - user defined global variable

-----

Question:

Does anybody know what the ";categories" plugin header line and the
"EffectNyquist::SetCommand" function (setting *breakenable*) are for?

- edgar


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
Gale (Audacity Team)

Re: Audacity Nyquist source code research for writing new documentation

Reply Threaded More More options
Print post
Permalink

| From edgar <[hidden email]>
| Wed, 18 Nov 2009 15:53:29 +0100
| Subject: [Audacity-nyquist] Audacity Nyquist source code research for writing new documentation

> Because it's (once again) a month ago, here is a summary of what
> happened last:
>
>  > Dave Storer asked:
>
>  > I there a way to carry over any information from one call to the next
>  > except by saving the state information in an external file?
>
>  > Leland wrote:
>
>  > There's a global variable called *SCRATCH* that can be used for
>  > this purpose. It is not restored between between tracks. A couple
>  > of new comment statements were added when I did the upgrade.
>
>  > ;codetype lisp | sal
>
>  > Tells Audacity the syntax to expect and how to pass it on to libnyquist.
>  > The default is lisp.  Only one type is allowed.
>
>  > ;debugflags trace | notrace | compiler | nocompiler
>
>  > Trace and notrace simply set Nyquist's "*tracenable*" global. This is
>  > similar to clicking the Debug button in the Nyquist prompt, but it
>  > allows the plug-in to control it instead.
>
>  > Compiler and nocompiler controls whether the generated Lisp code from
>  > the SAL compiler will be sent to stdout or to the output window in the
>  > Nyquist Workbench.
>
> -----
>
> Edgar - What I have so far...
>
> Looking at the source code of Audacity 1.3.10-alpha, 2009 Nov 18:
>
> According to "audacity/src/effects/Nyquist.cpp" the following control
> lines are currently recognized in Audacity Nyquist plugins:
>
> ;version    - the Audacity Plugin version (1, 2, or 3)
>
> // Version 1 only supported the slider widget
> // Version 2 added support for string widgets
> // Version 3 added support for choice widgets
>
> ;name       - the user-defined name of the plugin
> ;action     - the text in the message box when the effect is applied
> ;info       - some info text displayed in the plugin window
>
> ;control    - a slider widget
> ;string     - a string input widget
> ;choice     - a multiple-choice list-box widget
>
> ;categories - I have no idea what this is for ???

Edgar,

They are LV2 categories which we introduced as part of GSoC 2008:
http://wiki.audacityteam.org/index.php?title=LV2_Support#2008-06-04:_Category_support_working

We tried the categories out in the 1.3.6 Beta version of Audacity. It
was unpopular with the majority of users because of the extra
navigation involved to reach the effects.

It will not be re-introduced until it is provided with a way by which the
user can turn the grouping on and off in the interface.

It is turned on by compiling Audacity and uncommenting

//#define EFFECT_CATEGORIES

in Experimental.h.
.


Gale



------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
jsp67

Re: Audacity Nyquist source code research for writing new documentation

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)
you have the wrong person-you have been sendig me this stuff to much


| From edgar <[hidden email]>
| Wed, 18 Nov 2009 15:53:29 +0100
| Subject: [Audacity-nyquist] Audacity Nyquist source code research for writing new documentation

> Because it's (once again) a month ago, here is a summary of what
> happened last:
>
>  > Dave Storer asked:
>
>  > I there a way to carry over any information from one call to the next
>  > except by saving the state information in an external file?
>
>  > Leland wrote:
>
>  > There's a global variable called *SCRATCH* that can be used for
>  > this purpose. It is not restored between between tracks. A couple
>  > of new comment statements were added when I did the upgrade.
>
>  > ;codetype lisp | sal
>
>  > Tells Audacity the syntax to expect and how to pass it on to libnyquist.
>  > The default is lisp.  Only one type is allowed.
>
>  > ;debugflags trace | notrace | compiler | nocompiler
>
>  > Trace and notrace simply set Nyquist's "*tracenable*" global. This is
>  > similar to clicking the Debug button in the Nyquist prompt, but it
>  > allows the plug-in to control it instead.
>
>  > Compiler and nocompiler controls whether the generated Lisp code from
>  > the SAL compiler will be sent to stdout or to the output window in the
>  > Nyquist Workbench.
>
> -----
>
> Edgar - What I have so far...
>
> Looking at the source code of Audacity 1.3.10-alpha, 2009 Nov 18:
>
> According to "audacity/src/effects/Nyquist.cpp" the following control
> lines are currently recognized in Audacity Nyquist plugins:
>
> ;version    - the Audacity Plugin version (1, 2, or 3)
>
> // Version 1 only supported the slider widget
> // Version 2 added support for string widgets
> // Version 3 added support for choice widgets
>
> ;name       - the user-defined name of the plugin
> ;action     - the text in the message box when the effect is applied
> ;info       - some info text displayed in the plugin window
>
> ;control    - a slider widget
> ;string     - a string input widget
> ;choice     - a multiple-choice list-box widget
>
> ;categories - I have no idea what this is for ???
Edgar,

They are LV2 categories which we introduced as part of GSoC 2008:
http://wiki.audacityteam.org/index.php?title=LV2_Support#2008-06-04:_Category_support_working

We tried the categories out in the 1.3.6 Beta version of Audacity. It
was unpopular with the majority of users because of the extra
navigation involved to reach the effects.

It will not be re-introduced until it is provided with a way by which the
user can turn the grouping on and off in the interface.

It is turned on by compiling Audacity and uncommenting

//#define EFFECT_CATEGORIES

in Experimental.h.
.


Gale



------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
Stevethefiddle

Re: Audacity Nyquist source code research for writing new documentation

Reply Threaded More More options
Print post
Permalink
In reply to this post by edgar-rft
Question:

*SCRATCH* and LEN are not in the Nyquist manual, so I assume they are specific to Audacity's implementation. How "safe" is it to use these in Audacity plug-ins? (are they "permanent" features or might they disappear in later versions of Audacity?)

Steve D

edgar-rft wrote:
Hi Audacity Nyquist list,

Because it's (once again) a month ago, here is a summary of what
happened last:

 > Dave Storer asked:

 > I there a way to carry over any information from one call to the next
 > except by saving the state information in an external file?

 > Leland wrote:

 > There's a global variable called *SCRATCH* that can be used for
 > this purpose. It is not restored between between tracks. A couple
 > of new comment statements were added when I did the upgrade.

 > ;codetype lisp | sal

 > Tells Audacity the syntax to expect and how to pass it on to libnyquist.
 > The default is lisp.  Only one type is allowed.

 > ;debugflags trace | notrace | compiler | nocompiler

 > Trace and notrace simply set Nyquist's "*tracenable*" global. This is
 > similar to clicking the Debug button in the Nyquist prompt, but it
 > allows the plug-in to control it instead.

 > Compiler and nocompiler controls whether the generated Lisp code from
 > the SAL compiler will be sent to stdout or to the output window in the
 > Nyquist Workbench.

-----

Edgar - What I have so far...

Looking at the source code of Audacity 1.3.10-alpha, 2009 Nov 18:

According to "audacity/src/effects/Nyquist.cpp" the following control
lines are currently recognized in Audacity Nyquist plugins:

;version    - the Audacity Plugin version (1, 2, or 3)

// Version 1 only supported the slider widget
// Version 2 added support for string widgets
// Version 3 added support for choice widgets

;name       - the user-defined name of the plugin
;action     - the text in the message box when the effect is applied
;info       - some info text displayed in the plugin window

;control    - a slider widget
;string     - a string input widget
;choice     - a multiple-choice list-box widget

;categories - I have no idea what this is for ???

According to "audacity/src/effects/Nyquist.cpp" the following global
variables are set as a result of parsing the plugin header lines:

*sal-compiler-debug* - set by ";debugflags compiler | nocompiler"
*sal-call-stack*     - always reset to NIL
*tracenable*         - set by ";debugflags trace | notrace"
*breakenable*        - set by the "EffectNyquist::SetCommand" function
// Maybe "EffectNyquist::SetCommand" is called by external modules
// like the Nyquist Workbench?  I have found no other references in
// the Audacity source code.

According to "audacity/lib-src/libnyquist/nyx.c" the following global
variables are set by the Audacity Nyquist interface:

S             (SOUND)  - the Audacity sound object
LEN           (FLONUM) - length of the Audacity selection in samples
*SOUND-SRATE* (FLONUM) - sample frequency of the Audacity track
*WARP*        (LIST)   - the warp transformation environment variable

Variables which get NOT deleted or updated in subsequent invocations
of Nyquist plugins:

*SCRATCH* - user defined global variable

-----

Question:

Does anybody know what the ";categories" plugin header line and the
"EffectNyquist::SetCommand" function (setting *breakenable*) are for?

- edgar


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
Audacity-nyquist@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
jsp67

Re: Audacity Nyquist source code research for writing new documentation

Reply Threaded More More options
Print post
Permalink
Some javascript/style in this post has been disabled (why?)

wrong person

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
Al Dimond

Re: Audacity Nyquist source code research for writing new documentation

Reply Threaded More More options
Print post
Permalink
On Wednesday 18 November 2009 19:37:03 [hidden email] wrote:
> wrong person
>

You are receiving these messages because you are subscribed to the
audacity-nyquist mailing list.  Perhaps someone else tried to sign up
and typed your email address by mistake.  To unsubscribe you can go to
the following web page and enter your email address at the bottom of
the page to unsubscribe:

https://lists.sourceforge.net/lists/listinfo/audacity-nyquist

Hope this helps

 - Al

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
edgar-rft

*SCRATCH* and LEN (was: source code research ...)

Reply Threaded More More options
Print post
Permalink
In reply to this post by Stevethefiddle
Question:

 > *SCRATCH* and LEN are not in the Nyquist manual, so I assume they
 > are specific to Audacity's implementation.

Yes, both exist in Audacity only.

 > How "safe" is it to use these in Audacity plug-ins? (are they
 > "permanent" features or might they disappear in later versions
 > of Audacity?)

LEN is in Audacity Nyquist since the beginning, so you can count on it:
http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/devel/audacity-nyquist-en.htm#variables

*SCRATCH* is a new variable, which has not extensively tested.

Some first *SCRATCH* test results:

Preface:

In Lisp, using global variables like *SCRATCH* to store local results
of Lisp functions is considered very bad programming style. The reason
is that local variables are lexically scoped, what means that they
get automatically garbage-collected if not referenced any longer by
any other Lisp code, while global variables are dynamically scoped,
they only can get garbage-collected if explicitely set to NIL.

In one sentence:

Local function results referenced by global Lisp variables cannot
get automatically garbage-collected until all global references
are explicitely set to NIL.

In the case of *SCRATCH* in Audacity there happens something very
strange (from the Lisp point of view) but maybe very useful.

Audacity internals:

In Audacity, the Nyquist Lisp interpreter is only invoced once,
at the time when the first Nyquist plugin or some code from
"Effect > Nyquist Prompt" is applied. The initial state of the
*obarray* (the Lisp array where all symbol references are stored)
is backed-up into a C variable by the Audacity Nayquist interface.

After an Audacity Nyquist plugin is finished, the Nyquist Interpreter
keeps running, but the Lisp *obarray* gets restored by the Audacity
Nyquist interface from the initial value, which was stored in the
C variable. This way all user-defined functions and variables get
deleted from the Lisp *obarray*, and the Nyquist Lisp interpreter
will have it's initial state again, with exception of the *SCRATCH*
symbol, which is explicitely protected from deletion by the C-code
in the Audacity Nyquist interface.

Important: The "survival" of the *SCRATCH* symbol is a C-hack in the
Audacity Nyquist Interface, and NOT a build-in Nyquist behaviour.

As a side-effect of this C-hack all the backtracking pointers,
referenced by the *SCRATCH* symbol, get deleted, only the
reference to the *SCRATCH* symbol and it's values survive.

Practical usage:

The *SCRATCH* symbol offers a very ugly (but practically functional)
work-around for writing two-pass plugins.

You can write two-pass plugins as two separate plugins:

1. Write an "analysis" plugin, which stores it's result in the
*SCRATCH* variable (you can use lists to store multiple values).

Hint: an Audacity "analysis" plugin can generally also be written as a
"process" plugin, then the plugins will not appear in different menus.

2. Write a "process" plugin, using the results from the "analysis"
plugin, stored in the *SCRATCH* variable.

If the "analysis" plugin survives it's work without crashing Audacity
(the Audacity memory problems still exist during the plugin run-time),
then after the plugin has finished, all backtracking pointers,
referenced by the *SCRATCH* symbol, get deleted (by the C-hack in
the Audacity Nyquist interface), this way all allocated memory gets
freed, but all values of the *SCRATCH* symbol still exist and can be
re-used in subsequent plugins without causing huge memory allocations.

Practical examples:

If you want to see the memory allocation, start some memory monitor
(which tool depends on your operation system).

1. In Audacity, generate an audio track via "Generate > Tone".

2. Select the whole track, open "Effect > Nyquist Prompt" and type:

(setq *SCRATCH* (peak s ny:all))
(print *SCRATCH*)

Click "Debug" to apply the Nyquist code and see the "print" result.
In the memory monitor you can see the Audacity memory allocation
rising. Note that if the Audacity selection is too long, the "peak"
function will still be able to crash Audacity!

After the plugin has finished, the "Debug" window will appear with
the result of the "print" function. After closing the window the
plugin has finished and the memory gets freed again.

3. Now open Effect > Nyquist Prompt" a second time and type only:

(print *SCRATCH*)

Click "Debug" to see the "print" result. The "Debug" window will
appear with the result of the "print" function, which is still the
same as in the first example, but this time without any significant
memory allocation.

4. Because Lisp uses separate namespaces for variables and functions
also a user-defined *SCRATCH* function will survive:

Open Effect > Nyquist Prompt" again and type:

(defun *SCRATCH* () (print 'hello))
(*SCRATCH*)

Click "Debug" to see how the *SCRATCH* function prints "HELLO".

5. Open Effect > Nyquist Prompt" again and type only:

(*SCRATCH*)

Click "Debug" to see that the *SCRATCH* function still prints "HELLO".

Note: Defining Lisp functions in *star-notation* is even worse Lisp
style than binding local results to global variables. I only wanted
to demonstrate that this really works. Maybe there will appear some
situations where this could be used as another work-around.

6. Also the property list of the *SCRATCH* symbol will survive.

7. I still haven't tested what happens with *SCRATCH* OOP objects.

Summary:

 From the Lisp point of view the behaviour of the *SCRATCH* variable
is nothing but a really wacky hack, but in practical work the
*SCRATCH* variable can turn out as a really useful work-around.

I have noticed no really serious problems with *SCRATCH* so far.

- edgar



------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
edgar-rft

Re: Categories in plugin header lines (was: source code research...)

Reply Threaded More More options
Print post
Permalink
In reply to this post by Gale (Audacity Team)
Edgar asked:

 > ;categories - I have no idea what this is for ???

Gale wrote:

 > They are LV2 categories which we introduced as part of GSoC 2008:

http://wiki.audacityteam.org/index.php?title=LV2_Support#2008-06-04:_Category_support_working

 > We tried the categories out in the 1.3.6 Beta version of Audacity.
 > It was unpopular with the majority of users because of the extra
 > navigation involved to reach the effects.

 > It will not be re-introduced until it is provided with a way by
 > which the user can turn the grouping on and off in the interface.

Thanks, I think I will copy this into the documentation, so
Nyquist newbies will not be puzzled when reading the code of
existing Nyquist plugins.

- edgar

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
Roger Dannenberg

Re: *SCRATCH* and LEN

Reply Threaded More More options
Print post
Permalink
In reply to this post by edgar-rft
edgar wrote:

> Question:
>
>  > How "safe" is it to use these in Audacity plug-ins? (are they
>  > "permanent" features or might they disappear in later versions
>  > of Audacity?)
>
> *SCRATCH* is a new variable, which has not extensively tested.
>
> Some first *SCRATCH* test results:
>
> Preface:
>
> In Lisp, using global variables like *SCRATCH* to store local results
> of Lisp functions is considered very bad programming style.
Yes, but the point of *SCRATCH* is to provide some way for information
to survive from one invocation of a plug-in to the next. This is not a
case of local results but one of making local information global on purpose.

> The reason
> is that local variables are lexically scoped, what means that they
> get automatically garbage-collected if not referenced any longer by
> any other Lisp code, while global variables are dynamically scoped,
> they only can get garbage-collected if explicitely set to NIL.
>
> In one sentence:
>
> Local function results referenced by global Lisp variables cannot
> get automatically garbage-collected until all global references
> are explicitely set to NIL.
>
> In the case of *SCRATCH* in Audacity there happens something very
> strange (from the Lisp point of view) but maybe very useful.
>  
Depending on your point of view. The convention of putting asterisks (*)
around global variables in Lisp shows that globals are considered a
special case, but one that's common enough and important enough to have
developed a standard naming practice.
> Audacity internals:
>
> In Audacity, the Nyquist Lisp interpreter is only invoced once,
> at the time when the first Nyquist plugin or some code from
> "Effect > Nyquist Prompt" is applied. The initial state of the
> *obarray* (the Lisp array where all symbol references are stored)
> is backed-up into a C variable by the Audacity Nayquist interface.
>  
Strictly speaking, XLISP is initialized only once, meaning that the heap
and system variables are initialized only once, but the interpreter is
invoked once each time you run a plug-in. The interpreter is a function
written in C (that of course may call many other C functions in the
process of interpreting XLISP code).
> After an Audacity Nyquist plugin is finished, the Nyquist Interpreter
> keeps running,
Or rather the XLISP heap is retained after the interpreter returns to
the calling C function in Audacity.

> but the Lisp *obarray* gets restored by the Audacity
> Nyquist interface from the initial value, which was stored in the
> C variable. This way all user-defined functions and variables get
> deleted from the Lisp *obarray*, and the Nyquist Lisp interpreter
> will have it's initial state again, with exception of the *SCRATCH*
> symbol, which is explicitely protected from deletion by the C-code
> in the Audacity Nyquist interface.
>
> Important: The "survival" of the *SCRATCH* symbol is a C-hack in the
> Audacity Nyquist Interface, and NOT a build-in Nyquist behaviour.
>  
Or alternatively, restoring the *obarray* is a very non-standard C-hack.
A much more "normal" thing to do would be to leave the heap unaltered
(including *scratch* when a plug-in returns). In this way of looking at
things, the *scratch* behavior is completely normal Nyquist behavior and
the removal of all other globals set by the plug-in is the hack. In
retrospect, it might have been better to translate plug-ins so that all
top-level variables (that currently are globals) would be declared as
locals so that they would be cleaned up in the normal way, avoiding the
"hack" of manipulating the *obarray* when the plug-in returns. But then
this would make plug-ins have non-standard lisp behavior, so explaining
that would add some complexity to the system.

> As a side-effect of this C-hack all the backtracking pointers,
> referenced by the *SCRATCH* symbol, get deleted, only the
> reference to the *SCRATCH* symbol and it's values survive.
>
> Practical usage:
>
> The *SCRATCH* symbol offers a very ugly (but practically functional)
> work-around for writing two-pass plugins.
>
> You can write two-pass plugins as two separate plugins:
>
> 1. Write an "analysis" plugin, which stores it's result in the
> *SCRATCH* variable (you can use lists to store multiple values).
>
> Hint: an Audacity "analysis" plugin can generally also be written as a
> "process" plugin, then the plugins will not appear in different menus.
>
> 2. Write a "process" plugin, using the results from the "analysis"
> plugin, stored in the *SCRATCH* variable.
>
> If the "analysis" plugin survives it's work without crashing Audacity
> (the Audacity memory problems still exist during the plugin run-time),
> then after the plugin has finished, all backtracking pointers,
> referenced by the *SCRATCH* symbol, get deleted (by the C-hack in
> the Audacity Nyquist interface), this way all allocated memory gets
> freed, but all values of the *SCRATCH* symbol still exist and can be
> re-used in subsequent plugins without causing huge memory allocations.
>
> Practical examples:
>
> If you want to see the memory allocation, start some memory monitor
> (which tool depends on your operation system).
>
> 1. In Audacity, generate an audio track via "Generate > Tone".
>
> 2. Select the whole track, open "Effect > Nyquist Prompt" and type:
>
> (setq *SCRATCH* (peak s ny:all))
> (print *SCRATCH*)
>
> Click "Debug" to apply the Nyquist code and see the "print" result.
> In the memory monitor you can see the Audacity memory allocation
> rising. Note that if the Audacity selection is too long, the "peak"
> function will still be able to crash Audacity!
>
> After the plugin has finished, the "Debug" window will appear with
> the result of the "print" function. After closing the window the
> plugin has finished and the memory gets freed again.
>
> 3. Now open Effect > Nyquist Prompt" a second time and type only:
>
> (print *SCRATCH*)
>
> Click "Debug" to see the "print" result. The "Debug" window will
> appear with the result of the "print" function, which is still the
> same as in the first example, but this time without any significant
> memory allocation.
>
> 4. Because Lisp uses separate namespaces for variables and functions
> also a user-defined *SCRATCH* function will survive:
>
> Open Effect > Nyquist Prompt" again and type:
>
> (defun *SCRATCH* () (print 'hello))
> (*SCRATCH*)
>
> Click "Debug" to see how the *SCRATCH* function prints "HELLO".
>
> 5. Open Effect > Nyquist Prompt" again and type only:
>
> (*SCRATCH*)
>
> Click "Debug" to see that the *SCRATCH* function still prints "HELLO".
>
> Note: Defining Lisp functions in *star-notation* is even worse Lisp
> style than binding local results to global variables. I only wanted
> to demonstrate that this really works. Maybe there will appear some
> situations where this could be used as another work-around.
>
> 6. Also the property list of the *SCRATCH* symbol will survive.
>
> 7. I still haven't tested what happens with *SCRATCH* OOP objects.
>
> Summary:
>
>  From the Lisp point of view the behaviour of the *SCRATCH* variable
> is nothing but a really wacky hack, but in practical work the
> *SCRATCH* variable can turn out as a really useful work-around.
>
> I have noticed no really serious problems with *SCRATCH* so far.
>
> - edgar
>
>
>  
There should probably be some recommended protocols for dealing with
*scratch* since it is sort of a bottleneck for passing data among
plug-ins. I would recommend not setting *scratch* as a variable but
using it as a holder of property lists. That way, you get a whole name
space rather than a single variable name. To pass data from plugin
effectX-partA to effectX-partB,
    1) assign a property name based on the effect name, e.g. 'EFFECTX
    2) effectX-partA should delete any old property value:
remprop(quote(*scratch*), quote(effectx))
    3) effectX-partA should compute a new property value v and save it:
putprop(quote(*scratch*), v, quote(effectx))
    4) effectX-partB should access the property using
get(quote(*scratch*), quote(effectx))
    5) when effectX-partB finishes, it should remove the property:
remprop(quote(*scratch*), quote(effectx)), ...
    6) but there may be cases where you do some analysis and want to use
the analysis data multiple times. You might even have multiple analysis
plugins operating on different inputs to collect data to feed into a
plugin with multiple inputs. In this case (which might be quite common),
you should not call remprop(), but this has the problem of leaving data
on the *scratch* property list indefinitely, so ...
    7) In cases where *scratch* data is not deleted immediately after
use, there should be another effect, e.g. effectX-partCleanup, that
simply calls remprop(quote(*scratch*), quote(effectx)), allowing the
user to explicitly free up any data stored on the 'EFFECTX property. It
would be reasonable to omit the "effectX-partCleanup" effect if the data
stored on the property list has a maximum size of, say, 10KB. The
problem we want to avoid is properties with unbounded size getting left
in the heap until Audacity is restarted.

-Roger


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist
edgar-rft

Audacity and Nyquist 2009 - First update attempt

Reply Threaded More More options
Print post
Permalink
Hi all,

Here's a first attempt of an update:

http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/devel/audacity-nyquist-en.htm

At the moment only the english version is updated, the german version
is still the old text.

What's new?

New plugin header lines:

;categories
;codetype
;debugflags

All Audacity Nyquist Plugin widgets including all parameters:

* Slider Widgets
* Text Input Widgets
* Multiple-Choice Widgets

Plus Roger's proposal for the usage of the *scratch* symbol.

Even if a bit more organized than the old version, it's still a bit messy.
As I'm no native english speaking person, beside some hopfully not too many
bugs, if you find things that sound awkward, odd or just simply stupid,
please feel free to tell me better versions.

Also many examples are still in Lisp and not in SAL code.

- edgar

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Audacity-nyquist mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/audacity-nyquist