Information passed from Audacity to Nyquist

Suggested feature request:

Some mechanism by which Nyquist can know if it is the first track of a multi-track selection.
One possible implementation could be if Audacity passed to Nyquist the number of selected tracks. A plug-in could then count down the number of tracks as a property of scratch and reset itself when the number of tracks remaining = 0.

What do you think?

I think, all data refering to s should be transfered by audacity in a property list. In that way we could read the required information via the “get” function. For example:

(print (get 's 'name)); Prints the "track 1" or  "Bass drum"

The normal handling of s wouldn’t be affected in any way. No new variables would be introduced, which could accidentally be overwritten by the programmer, as it may be the case with the variable “len”. We could include such details as:

  • name; user-defined name of current track, nil if not assigned yet
  • start-time-track; Track start time, is greater than zero, if the track is already moved to the right.
  • stop-time; absolute to left boundary (zero)
  • Start-time-selection; position within the track;also absolute
  • Stop-time-selection
  • total-tracks; number of tracks that are selected
  • rms; any volume information if available
  • envelope; List with envelope points
  • to be continued…

This list could successively be expanded during the test phase i.e. one element after another.
The “total-track” property would be ideal as a starting point because

  1. the information is read-only.
  2. A lot of existing plug-ins would profit immediately from it.
  3. A great deal of test algorithm with flags etc. could be skipped, if this property was present.
  4. Error and warning messages could be given out at the start of a multi track execution, without going through the whole process.
  5. if a even number of tracks is required, the execution will stop before the last (odd) track.

As a next step, a property could be introduced, which can be modified by Nyquist. If we take the “name” property as an example, click-track.ny could return “Click-Track 65 bpm (8/4)”.

What a bummer that I am no C programmer. Unfortunately, I don’t know how a property list can be attached to “s” from within the C code. nevertheless a property list for the sound variable seems to be the proper way. What do you think?

Yes I agree. I wrote something along the same lines a long time ago: Sample Printer - #19 by steve

It would often be useful if Nyquist knew more about “s”.
Audacity has information about the track that is not available to Nyquist.
The number of samples is passed to Nyquist in the variable “LEN” and the actual audio data in “S”, but that’s all.
What I would like to see is additional track data passed to Nyquist, possibly as a property list, to include:

Track name,
Channel allocation (for mono tracks),
Peak Amplitude (solves the Normalising issue for some situations),
RMS,
Start time,
Envelope Points,
Bit-depth.

Those were some ideas off the top of my head, not a definitive list. It’s interesting to see that you came up with such a similar idea.
I also like the idea of taking an incremental approach.

At some point I’ll start a more formal proposal for this feature, which you will of course be very welcome to contribute to.

You can always count on my support and contribution. Let us start a campaign…
Hopefully, our request will not end up as priority level 97…

It may be interesting, what is all stored in a aup file. This is a example project with 1 track, a 1 second mono sine tone that is starting at 1.0 s and additionally clipped at 1.5 s to 2.0 s.

<?xml version="1.0" standalone="no" ?>
<!DOCTYPE project PUBLIC "-//audacityproject-1.3.0//DTD//EN" "http://audacityteam.org/xml/audacityproject-1.3.0.dtd" >
<project xmlns="http://audacityteam.org/xml/" projname="example project_data" version="1.3.0" audacityversion="2.0.2-alpha-Aug  8 2012" sel0="1.5000000000" sel1="2.0000000000" vpos="0" h="0.0000000000" zoom="553.0000000000" rate="44100.0">
	<tags/>
	<wavetrack name="Sine 440 1 second" channel="2" linked="0" mute="0" solo="0" height="150" minimized="0" isSelected="1" rate="44100" gain="0.707946" pan="-0.5">
		<waveclip offset="0.00000000">
			<sequence maxsamples="262144" sampleformat="262159" numsamples="66150">
				<waveblock start="0">
					<simpleblockfile filename="e000091c.au" len="66150" min="-0.8" max="0.8" rms="0.402329"/>
				</waveblock>
			</sequence>
			<envelope numpoints="1">
				<controlpoint t="1.499977324263" val="1.000000000000"/>
			</envelope>
		</waveclip>
		<waveclip offset="1.50000000">
			<sequence maxsamples="262144" sampleformat="262159" numsamples="22050">
				<waveblock start="0">
					<simpleblockfile filename="e0000d1e.au" len="22050" min="-0.8" max="0.8" rms="0.330154"/>
				</waveblock>
			</sequence>
			<envelope numpoints="1">
				<controlpoint t="0.000000000000" val="1.000000000000"/>
			</envelope>
		</waveclip>
	</wavetrack>
</project>

There are some of the points in our list clearly represented. Especially track-name, channels, rms, clip start, envelope points etc.
I think it would also be useful to include the Audacity version in our property-list thus providing a control instrument for the backward compatibility.

The channel property would be extremely helpful for generate plug-ins, where we for the time being have no chance to know their number.

What about labels?

Nyquist can create labels, but can’t read them.
An obvious application that comes to mind is for generating cue sheets for tracks that are to be split with Export Multiple.
Another possible applications includes marking positions for effects that change over time, thus providing rudimentary “automation”.
It may also be useful for 2-pass effects in situations where it would be useful for the user to be able to inspect detected events, for example for detecting, then repairing clicks.

Rather than passing labels as properties of “S” it may be better to have a separate variable for label tracks.
Alternatively, the global variable “S” could be redefined as “track content” rather than “audio track content”, thus if a label track is selected, “S” is a list of lists in the same way as Nyquist sends label data to Audacity.

It’s unfortunate that “S” was chosen as the symbol for the audio track data, not only because it implies that it must be “sound”, but because “S” was already defined as 1/4 beat in Adagio notation (http://www.cs.cmu.edu/~rbd/doc/nyquist/part2.html#index43)

I would rather not re-define the variable s and stick to the property list solution. If a audiotrack has a associated label track, the property “labels” will contain the list, otherwise none. If we store the labels in s, we have to check if s is a sound, an array or a list.
Furthermore, it would thus be possible to return a modified sound s and at the same time create or manipulate a linked label track. I reckon that it wouldn’t make much sense to call a plug-in with the label track alone. I do not use label, hence I don’t know how they work. However, Ithought they were always bound to the Audio track above.

Another cool thing would be to receive midi data from tracks. Since Nyquist was created for sound synthesis, this would open up a big new field. It would be somehow be the opposite of label tracks. Audacity would pass an empty variable s and the midi data in another property. We could either modify this data and return it or render it to the variable s. Audacity would simply insert s above the midi track. However, thats something for the far future, isn’t it.

Label tracks are not bound to audio tracks, though they may be “linked” to tracks if Sync Lock is enabled.
You can have as many of them as you like and they can be moved up or down as can audio or midi tracks.
A project could have label tracks and MIDI tracks but no audio tracks.

I’m not sure that it makes sense to pass MIDI data or Label data as properties of “S” because such data is in no way bound to sounds.
It would imho be more rational to either (a) use different global variables for different track types, or (b) use one global variable that can carry data from any track type.

Perhaps a solution would be to introduce one new global called Track or something similar. The idea being that this would eventually take over from “S”. (“s” was never a good idea imho, but “S” will need to be kept for a long time so as to provide backward compatibility).

The Track variable could be a sound, an array of sounds, MIDI data or a list.
I’m not sure how MIDI data would be handled, perhaps as a named stream, but that’s a long way off.

Currently, for “S” we can assume that if the data from Audacity is not a sound, then it is a stereo array. For Tracks we could no longer make that assumption. If Audacity ever gets full multi-channel capability, then that assumption may break anyway.

Yes, a new variable is most likely to be introduced for label tracks. But I am not sure that we should drop the s variable. At a first glance, multi channel sounds could also be given over as an array, but I imagine that the format (4.1 surround Dolby etc.)should also be given over as a property, since not all multi channel sounds are alike, even if there are the same number of channels (e.g. phases are reversed for surround etc).
For the treatment of midi data, there is a special library included within Audacity but I am not yet familiar with its functionality neither how we could write an interface to Nyquist. Normally, the whole midi data should be passed to Nyquist because of the initial commands. The events that have no influence on the output should be filtered out prior to the rendering of the selection. Nevertheless, it may be a good idea to couple pure midi to a rendered result, otherwise the original data would be overwritten.
But those are dreams of the future. Let us consider, how the work flow of a prospective plug-in would look like. Maybe the variable s should exist parallel to our new global variable - it’s only a pointer after all - and the program would firstly look which audacity version it is running under. Old plug-ins would still work with the s variable without this checking. New Plug-ins would work exclusively with the new global variable track or so, at least if they work with labels, multichannel-sounds etc. and if there is no workaround with the good old ‘s’ (e.g. shift the sound with silence instead of passing a new starting point). The question is, to which variable the additional property list should be appended, maybe both. What should be the first step, if we want to stick to the incremental approach? Shall we introduce the track variable right away and build up the property list for both variables in parallel? And when the limits of s are reached, only expand the track variable with label tracks etc.?

As my old boss used to say “we’re singing from the same sheet” :smiley:

Yes I’m definitely for an incremental approach.
I think that it is worthwhile for us to consider to bigger picture about where we would like this to go, even though implementing it will depend a lot on how Audacity works internally. At least we can paint a picture for the developers of how we would like it to go.

Nyquist versions are currently up to “version 3”. The possibility of a major new variable could be introduced as a feature of “version 4” plug-ins. Audacity already checks the plug-in version number before loading the plug-in.

The Audacity MIDI features are very much “Experimental” and are mostly the work of Roger Dannenberg, the same person that invented Nyquist.

Have you seen the “Nyquist Wish List” post? https://forum.audacityteam.org/t/nyquist-wish-list/15530/1
I was wondering how to go about presenting the ideas in there. Not all of the ideas there are good ideas :smiley:
Perhaps a good approach would be to propose a specification for “version 4” plug-ins?

Yes, if you’ll sing one quarter tone above the key we will assuredly sing in tune… :smiley:
I fancy that we shouldn’t wait with the global variable explicitly until Version 4 plug-ins can be launched.
In Version 4 will presumably much more changes be involved, which refer mostly to the GUI. For example could the following appear in the header:

;Help "http://www.plug-in-help.org/nonsense.htm"
;; would add a help button, that jumps to the url. 
;Relaunch "Preview"
;Would add a new button named "preview" and set the relaunch-preview  flag.
;; Every time the button would be pressed, the plug-in would newly be started.
;Relaunch "Analyse"
;Relaunch "About"
;; other possibilities for this button.

And there are a lot of new ideas on the wishlist (for good or evil…).
A plug-in of the version 1 could equally work with a property list, if it firstly checks the existence of such a list.
We can certainly go for both goals, independendly from one another. I, for one, have this impression.

Maybe the best way would be to gather the ideas on a WIKI page. In these forum threads one is most likely to loose the thread…
We could thus present our ideas on one page, with a table of contents and provide a time/priority table with the proper progress or status information.

Yes it could, but I’d suggest that if a plug-in requires the property list then it should be labelled as version 4.
If someone is using an old version of Audacity that does not supply the property list, then a plug-in that requires it will not work and so should not be listed in the Effect menu. The plug-in version number provides a convenient way for older versions of Audacity to reject plug-ins that they do not support.

The persistent variable scratch is only supported in later versions of 1.3.x and 2.x, so really (imho) any plug-in that requires scratch should be version 3 (minimum) even if they only have slider controls.

Hi Steve
I am terribly sorry for the late reply but my hard disk decided two weeks ago that it was time to leave this miserable world with a final roar.
However, in the matter at hand our opinions seems to go astray.
If we wait for the version 4 of the plug-in interface for our property list to be introduced, several disadvantages seem to loom up.

  • The property list must be fully assembled, no features can incrementely be added.
  • New plug-ins that do not use enhanced GUI features but the “plist” can’t be written prior to version 4.
  • Internal functionality of Nyquist is strongly bound to the graphical interface and looses somehow its independence.
  • The whole process could take another 2 years before it shows any results.
  • When version 4 eventually is launched, a whole bunch of new functionality is added and a wide range of possible bugs presents itself at once.

Let us look at an imaginary example if the two things were treated separately :
Due to some lucky circumstances, we have found a developer,who was able to set up a property list for the variable s and as a first thing the name of the track is passed from and to Audacity. All generate plug-ins would now be abel to assign a name to the track they’ve created. If no property is found, nothing is passed but the plug-in would still work with old versions of Audacity. And since scratch is presumably not used in those plug-ins, you’re likely not restricted to versions 1.3.12 and above. Thus the newest plug-ins that don’t make use of enhanced controls could be loaded into old versions without substantial drawbacks.
Certainly, there will be some properties for which a workaround doesn’t make any sense (e.g. the manipulation of label tracks) and for those a binding to version 4 is appropriate. However, we should differentiate the two kinds of properties and thus gain a bigger amount of backward compatibility. Don’t misunderstand me, I am always keen for the newest Audacity versions and quickly discard the old ones. However, for once I’ll play the devils advocate. I admit that the main reason is to make a start with something concrete i.e. the testing of the realization of this property exchange.
In my opinion, the above example with the name property would be an ideal starting point, especially with the build-in generate effects like cllick-ttrack or tone generate.

No problem, glad to see you back on line.

That’s not what I’m suggesting.

Since the introduction of version 3 plug-ins there have been quite a few features added to Audacity/Nyquist. Some that come to mind are SCRATCH , GET-ENV , ROUND … I’m sure there are others. So the plug-in version number does not indicate which versions of Audacity the plug-in will work with, it indicates which versions of Audacity it will not work in. Version 3 plug-ins will not work in Audacity 1.3.4 or earlier.

What I’m suggesting in introducing version 4 plug-ins is a fairly arbitrary demarcation. It would perhaps have been helpful if version 4 was introduced with Audacity 2.0 so as to avoid the current confusion that version 3 plug-ins may or may not work in 1.3.x. Mark the plug-in as version 4 and it indicates that 1.3.x is “not supported” (and it will not show up in 1.3.x). Gale Andrews has suggested that new plug-ins should include a comment to say the minimum version of Audacity that the plug-in will work with, but that’s quite a burden on plug-in authors if they need to test in multiple obsolete versions of Audacity. As it currently stands it’s a bit of a “chicken and egg” situation.

What I’m suggesting is that introducing an “S” property list would be as good a time as any to bump the plug-in version number.
New properties could be added incrementally. All that “version 4” would mean is that the plug-in is not supported in versions of Audacity earlier than 2.something.
I know it’s not ideal. Is there a better way to handle version numbers for plug-ins?

Ok, I guess, I can see the picture now. Roughly speaking we have a time line where the different properties have their introduction date. Somewhere in the middle, i.e. as a milestone, version 4 is oficially launched. In addition that’s also the time when we will use exclusively our track variable (for plug-ins of this type), rather than s.
I think it’s time to set up a road map for all that’s to come. Ideally would be if we could create a temporary sub-forum, something like “Roadmap Version 4 Plug-ins”.
The topics of this Forum would all be alike. For example: Topic “Ticket property (open)”. Such a ticket would serve as a basis for the formal request (to implement a property or a feature). Consequently, the first post had also to be of a formal structure. The description would include such things as “name”, “proposed introduction time”, “Data structure” and many more. I’ll try to assembly an example in the next post. All other posts can be used freely to commend and propose modifications.

PS.
The version problem is not restricted to Audacity. It seems that we have to drag some things a little farther. However, there’s also the saying that you have to know when to cut off the old tresses.

As promised, here an example how a ticket could be structured
I’ve made a template in a work sheet which will facilitate new postings of this kind.

Ticket status:
open
Refers to:
Nyquist, new Entry in the property list of track.
Name:
name
Usage example LISP:
(get 'track 'name)
Description:
Holds the track name as it appears in the trackview
Data type:
String
Data range:
“Spur 5” - automatically generated name in the proper language.
“Bass drum” - Previously assigned name by user.

Dependencies:
Property ‘name-assigned’
with nil = no name assigned yet
T = Name assigned by User

Advantages:
If passed to Nyquist, the Name can be used for Headers in Analyse Plug-ins. E.g. when plotting sample data to a file or the screen.
The names can also be modified and passed back to Audacity. This allows (generate) plug-ins to assign a descriptive name, e.g. “saw-tooth 1020 Hz” or “Click 146 bpm 8/4”.
The property ‘name-assigned’ determines if the name can be overwritten or if the information provided by the plug-in should be appended or omitted.

Disadvantages:
The passing of the name shouldn’t be a problem, > however, in generate plug-ins, no sound is passed from Audacity, thus track is empty but still has to pass a property list anyway. > There shouldn’t be any conflicts with other properties The dependent property ‘name-assigned’ should be treated as read-only variable and can only be modified by Audacity.
Notes:
As an alternative, Audacity could pass an empty string, if no name is assigned yet and thus the dependent property ‘name-assigned’ could be left out.
However, the consequence would be that undefined names that appear in a file header or similar output would always be in the same language (English) or not existent at all. This doesn’t seem satisfying since Audacity knows the translation for “Track” in the GUI language and also knows what number the track has in the track view.

Workarounds for previous Audacity versions:
None. There is no way for Nyquist to find out what name the processed track has.
Change history:
27.09.2012 First posting
28.09.2012 Removed “s and” from “property list of s and track” under "> Refers to:> "
28.09.2012 Removed “No issues identified yet.” and "The assignement of new names by the plug-in involves the same routines as those used for the user input of names. " under "> Disadvantages:> "
and new text added.

I haven’t included the date for the introduction of the property. I think that the priorities could easily be set in a summarizing topic at the top of the proposed new sub-fourum.
Would this be a possible approach, or are there other ideas?

Just a very quick note as I need to go out shortly.
Audacity does not pass “S” to Nyquist for generate plug-ins, only for process (effects) and analyze plug-ins.

The variable s is always in existence. It is stored in the obarray hash table. It is of course only a symbol within a generate plug-in, neither a sound nor an array and contains no samples. However, the fact that it is defined as a global variable is enough to put a property on it. The following code inserted in a generate plug-in

(print s)
(print (type-of 's))
(print (boundp 's))
(setf (get 's 'test) "nil")
(print (symbol-plist 's))

returns

NIL; value of s
SYMBOL; Type of s
T; s exists
(TEST "nil"); The property list with 1 entry

But that isn’t what I asked for (The Text above is only an example and not subject of the diskussion).

Hi, just popped back in before going out again…


Yes, but you also wrote in your example ticket: “No issues identified yet.”
I’m identifying an issue.


The issue is, that is not what is returned from a generate plug-in.

Try running this and press Debug:

;nyquist plug-in
;version 1
;type generate
;name "a test"

;control dummy "Dummy" int "" 0 0 1

(print s)
(print (type-of 's))
(print (boundp 's))
(setf (get 's 'test) "nil")
(print (symbol-plist 's))

For generate plug-ins “S” has nothing to do with the audio track or what it contains.
In generate type plug-ins “S” is the symbol for the Adagio 1/16 note Time/Frequency Transformation

As I wrote previously, I don’t think that using “S” for the Audacity sound object was the best of ideas.

I think that we need to avoid going into too much detail in the specification until we have expert input from someone that knows what is going on in the C+ internals of Audacity. What we can safely specify is the functionality that we would like, but not necessarily how to achieve it. For example, we know that Nyquist receives the sound object from Audacity bound to “S”, but when Nyquist returns a sound, it does not need to be bound to anything, it just needs to be the returned value. So the mechanism for returning a track name to Audacity will be completely different from the mechanism by which Nyquist receives data from Audacity. I don’t know enough about the C++ internals to know how returning a track name to Audacity may best be achieved and I’m happy to leave that up to the developer that writes the code for it.

s is only defined as an adagio variable at the very beginning i.e. during the startup of Audacity.
If you insert a tone with the tone generate plug-in, s will no more have any value other than nil. therefore, s can’t be used reliable as a note value altogether (the bug you already reported).
As you can see in the example above, the property is read out from track what surely is the way to go and s doesn’t need a copy of the property list at all (thats a point to correct above).
However, track needs in contrast the pointer to the sound that is saved in s.
The greatest problem we have to face is how an property list can be created from within C, that doesn’t know such a data type.
I assume that track and its property list must be defined during the xlisp initialisation in a *.LSP file and the desired values must be passed via the typical data types integer, string, long, double, boolean and so on. If I am right, Roger uses sometimes the variable RSLT to transfer data between C and XLISP.
http://www.cs.cmu.edu/~rbd/doc/nyquist/part18.html#index1251
(There are some interesting facts about the C routines and xlisp, even if it is not related to Audacity itself.)

Well, it seems that your connections are required for this task…