1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-04-30 15:49:41 +02:00

A subset of the original v4 patch (which will become v5 eventually)

The main operational difference is that for v4 effect onward, the 
sound name will now be *TRACK*.  This will not affect existing
effects since they use version number 3 or less.

This also provides the Nyquist effect with much more information about
the current processing:

Variable       Property    What
*AUDACITY*     VERSION     current Audacity version number

*SYSTEM-DIR*   BASE        Audacity install path
*SYSTEM-DIR*   DATA        Audacity data path
*SYSTEM-DIR*   HELP        Audacity help path
*SYSTEM-DIR*   TEMP        Audacity temp file path
*SYSTEM-DIR*   PLUGIN      Audacity search path for Nyquist plugins

*PROJECT*      RATE        current project sample rate
*PROJECT*      TRACKS      total number of tracks in the project
*PROJECT*      WAVETRACKS  number of wave tracks in the project
*PROJECT*      LABELTRACKS number of label tracks in the project
*PROJECT*      MIDITRACKS  number of midi tracks in the project
*PROJECT*      TIMETRACKS  number of time tracks in the project

*SELECTION*    START       start time of current selection
*SELECTION*    END         end time of current selection
*SELECTION*    TRACKS      number of tracks in the current selection
*SELECTION*    CHANNELS    number of channels in the current selection
*SELECTION*    LOW-HZ      low frequency from spectrogram (if available, else nil)
*SELECTION*    CENTER-HZ   center frequence (calculated) (if available, else nil)
*SELECTION*    HIGH-HZ     high frequence from spectrogram (if available, else nil)
*SELECTION*    BANDWIDTH   bandwidth in octaves (calculated) (if available, else nil)
*SELECTION*    PEAK-LEVEL  peak amplitude for the current selection

*TRACK*        INDEX       1-based index of track being processed
*TRACK*        NAME        name of track
*TRACK*        TYPE        type of track: wave, midi, label, time
*TRACK*        VIEW        track view: Waveform,  Waveform (dB), etc.
*TRACK*        CHANNELS    number of channels in the track
*TRACK*        START-TIME  start time of track
*TRACK*        END-TIME    end time of track
*TRACK*        GAIN        track gain
*TRACK*        PAN         track pan
*TRACK*        RATE        sample rate of track
*TRACK*        FORMAT      sample format: 16 (int), 24 (int), 32.0 (float)
*TRACK*        CLIPS       list of start/end times for clips for each channel
This commit is contained in:
lllucius 2014-11-13 16:38:20 +00:00
parent bce372bfee
commit 4c0aa60871
5 changed files with 265 additions and 28 deletions

View File

@ -75,6 +75,7 @@ LOCAL int nyx_first_time = 1;
LOCAL LVAL nyx_obarray;
LOCAL FLOTYPE nyx_warp_stretch;
LOCAL long nyx_input_length = 0;
LOCAL char *nyx_audio_name = NULL;
/* Suspension node */
typedef struct nyx_susp_struct {
@ -454,6 +455,7 @@ void nyx_init()
argv[0] = "nyquist";
xlisp_main_init(1, argv);
nyx_audio_name = NULL;
nyx_os_cb = NULL;
nyx_output_cb = NULL;
@ -505,7 +507,7 @@ void nyx_cleanup()
// Make sure the sound nodes can be garbage-collected. Sounds are EXTERN
// nodes whose value does not get copied during a full copy of the obarray.
setvalue(xlenter("S"), NIL);
setvalue(xlenter(nyx_get_audio_name()), NIL);
// Free excess memory segments - does a gc()
freesegs();
@ -520,6 +522,11 @@ void nyx_cleanup()
// Reset vars
nyx_input_length = 0;
if (nyx_audio_name) {
free(nyx_audio_name);
nyx_audio_name = NULL;
}
#if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS
printf("\nnyx_cleanup\n");
xmem();
@ -587,6 +594,25 @@ void nyx_capture_output(nyx_output_callback callback, void *userdata)
nyx_output_ud = userdata;
}
char *nyx_get_audio_name()
{
if (!nyx_audio_name) {
nyx_audio_name = strdup("S");
}
return nyx_audio_name;
}
void nyx_set_audio_name(const char *name)
{
if (nyx_audio_name) {
free(nyx_audio_name);
nyx_audio_name = NULL;
}
nyx_audio_name = strdup(name);
}
void nyx_set_audio_params(double rate, long len)
{
LVAL flo;
@ -670,7 +696,7 @@ void nyx_set_input_audio(nyx_audio_callback callback,
}
}
setvalue(xlenter("S"), val);
setvalue(xlenter(nyx_get_audio_name()), val);
xlpop();
}
@ -862,7 +888,7 @@ nyx_rval nyx_eval_expression(const char *expr_string)
xlpop(); // unprotect expr
setvalue(xlenter("S"), NIL);
setvalue(xlenter(nyx_get_audio_name()), NIL);
gc();

View File

@ -61,6 +61,9 @@ extern "C"
void *userdata,
int num_channels,
long len, double rate);
char *nyx_get_audio_name();
void nyx_set_audio_name(const char *name);
nyx_rval nyx_eval_expression(const char *expr);

View File

@ -31,8 +31,7 @@ void LoadNyquistEffect(wxString fname)
void LoadNyquistPlugins()
{
wxArrayString audacityPathList = wxGetApp().audacityPathList;
wxArrayString pathList;
wxArrayString pathList = EffectNyquist::GetNyquistSearchPath();
wxArrayString files;
unsigned int i;
@ -41,16 +40,6 @@ void LoadNyquistPlugins()
EffectManager::Get().RegisterEffect(effect);
// Load .ny plug-ins
for(i=0; i<audacityPathList.GetCount(); i++) {
wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH;
wxGetApp().AddUniquePathToPathList(prefix + wxT("nyquist"),
pathList);
wxGetApp().AddUniquePathToPathList(prefix + wxT("plugins"),
pathList);
wxGetApp().AddUniquePathToPathList(prefix + wxT("plug-ins"),
pathList);
}
wxGetApp().FindFilesInPathList(wxT("*.ny"), pathList, files);
#ifdef __WXGTK__
wxGetApp().FindFilesInPathList(wxT("*.NY"), pathList, files); // Ed's fix for bug 179

View File

@ -50,9 +50,13 @@ effects from this one class.
#include <wx/choice.h>
#include "../../AudacityApp.h"
#include "../../LabelTrack.h"
#include "../../FileNames.h"
#include "../../Internat.h"
#include "../../LabelTrack.h"
#include "../../Project.h"
#include "../../ShuttleGui.h"
#include "../../WaveClip.h"
#include "../../WaveTrack.h"
#include "../../widgets/valnum.h"
#include "Nyquist.h"
@ -83,6 +87,8 @@ EffectNyquist::EffectNyquist(wxString fName)
mIsSal = false;
mOK = false;
mVersion = 4;
mStop = false;
mBreak = false;
mCont = false;
@ -259,12 +265,16 @@ void EffectNyquist::Parse(wxString line)
// We support versions 1, 2 and 3
// (Version 2 added support for string parameters.)
// (Version 3 added support for choice parameters.)
// (Version 4 added support for project/track/selection information.)
if (len >= 2 && tokens[0] == wxT("version")) {
if (tokens[1] != wxT("1") && tokens[1] != wxT("2") && tokens[1] != wxT("3")) {
long v;
tokens[1].ToLong(&v);
if (v < 1 && v > 4) {
// This is an unsupported plug-in version
mOK = false;
return;
}
mVersion = (int) v;
}
if (len >= 2 && tokens[0] == wxT("name")) {
@ -682,8 +692,114 @@ bool EffectNyquist::Process()
mBreak = false;
mCont = false;
mTrackIndex = 0;
mDebugOutput = "";
if (mVersion >= 4)
{
AudacityProject *project = GetActiveProject();
mProps = wxEmptyString;
mProps += wxString::Format(wxT("(putprop '*AUDACITY* (list %d %d %d) 'VERSION)\n"), AUDACITY_VERSION, AUDACITY_RELEASE, AUDACITY_REVISION);
mProps += wxString::Format(wxT("(putprop '*SYSTEM-DIR* \"%s\" 'BASE)\n"), FileNames::BaseDir().c_str());
mProps += wxString::Format(wxT("(putprop '*SYSTEM-DIR* \"%s\" 'DATA)\n"), FileNames::DataDir().c_str());
mProps += wxString::Format(wxT("(putprop '*SYSTEM-DIR* \"%s\" 'HELP)\n"), FileNames::HtmlHelpDir().RemoveLast().c_str());
mProps += wxString::Format(wxT("(putprop '*SYSTEM-DIR* \"%s\" 'TEMP)\n"), FileNames::TempDir().c_str());
wxArrayString paths = EffectNyquist::GetNyquistSearchPath();
wxString list;
for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++)
{
list += wxT("\"") + paths[i] + wxT("\" ");
}
mProps += wxString::Format(wxT("(putprop '*SYSTEM-DIR* (list %s) 'PLUGIN)\n"), list.RemoveLast().c_str());
TrackListIterator all(project->GetTracks());
Track *t;
int numTracks = 0;
int numWave = 0;
int numLabel = 0;
int numMidi = 0;
int numTime = 0;
for (t = all.First(); t; t = all.Next())
{
switch (t->GetKind())
{
case Track::Wave: numWave++; break;
case Track::Label: numLabel++; break;
#if defined(USE_MIDI)
case Track::Note: numMidi++; break;
#endif
case Track::Time: numTime++; break;
default: break;
}
numTracks++;
if (t->GetLinked())
{
all.Next();
}
}
mProps += wxString::Format(wxT("(putprop '*PROJECT* (float %g) 'RATE)\n"), project->GetRate());
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'TRACKS)\n"), numTracks);
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'WAVETRACKS)\n"), numWave);
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'LABELTRACKS)\n"), numLabel);
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'MIDITRACKS)\n"), numMidi);
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'TIMETRACKS)\n"), numTime);
SelectedTrackListOfKindIterator sel(Track::Wave, mOutputTracks);
int numChannels = 0;
numTracks = 0;
for (WaveTrack *t = (WaveTrack *) sel.First(); t; t = (WaveTrack *) sel.Next()) {
numTracks++;
numChannels++;
if (mT1 >= mT0) {
if (t->GetLinked()) {
numChannels++;
sel.Next();
}
}
}
mProps += wxString::Format(wxT("(putprop '*SELECTION* (float %g) 'START)\n"), mT0);
mProps += wxString::Format(wxT("(putprop '*SELECTION* (float %g) 'END)\n"), mT1);
mProps += wxString::Format(wxT("(putprop '*SELECTION* %d 'TRACKS)\n"), numTracks);
mProps += wxString::Format(wxT("(putprop '*SELECTION* %d 'CHANNELS)\n"), numChannels);
wxString lowHz = wxT("nil");
wxString highHz = wxT("nil");
wxString centerHz = wxT("nil");
wxString bandwidth = wxT("nil");
#if defined(EXPERIMENTAL_SPECTRAL_EDITING)
if (mF0 >= 0.0) {
lowHz.Printf(wxT("(float %g)"), mF0);
}
if (mF1 >= 0.0) {
highHz.Printf(wxT("(float %g)"), mF1);
}
if ((mF0 >= 0.0) && (mF1 >= 0.0)) {
centerHz.Printf(wxT("(float %g)"), sqrt(mF0 * mF1));
}
if ((mF0 > 0.0) && (mF1 > mF0)) {
bandwidth.Printf(wxT("(float %g)"), log(mF1 / mF0)/log(2.0));
}
#endif
mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'LOW-HZ)\n"), lowHz.c_str());
mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'CENTER-HZ)\n"), centerHz.c_str());
mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'HIGH-HZ)\n"), highHz.c_str());
mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'BANDWIDTH)\n"), bandwidth.c_str());
}
// Keep track of whether the current track is first selected in its sync-lock group
// (we have no idea what the length of the returned audio will be, so we have
// to handle sync-lock group behavior the "old" way).
@ -779,16 +895,7 @@ bool EffectNyquist::ProcessOne()
{
nyx_rval rval;
if (GetEffectFlags() & INSERT_EFFECT) {
nyx_set_audio_params(mCurTrack[0]->GetRate(), 0);
}
else {
nyx_set_audio_params(mCurTrack[0]->GetRate(), mCurLen);
nyx_set_input_audio(StaticGetCallback, (void *)this,
mCurNumChannels,
mCurLen, mCurTrack[0]->GetRate());
}
nyx_set_audio_name(mVersion >= 4 ? "*TRACK*" : "S");
wxString cmd;
@ -810,6 +917,97 @@ bool EffectNyquist::ProcessOne()
}
#endif
if (mVersion >= 4) {
cmd += mProps;
// Set the track TYPE and VIEW properties
wxString type;
wxString view;
wxString bitFormat;
switch (mCurTrack[0]->GetKind())
{
case Track::Wave:
type = wxT("wave");
switch (((WaveTrack *) mCurTrack[0])->GetDisplay())
{
case WaveTrack::WaveformDisplay: view = wxT("Waveform"); break;
case WaveTrack::WaveformDBDisplay: view = wxT("Waveform (dB)"); break;
case WaveTrack::SpectrumDisplay: view = wxT("Spectrogram"); break;
case WaveTrack::SpectrumLogDisplay: view = wxT("Spectrogram log(f)"); break;
case WaveTrack::PitchDisplay: view = wxT("Pitch (EAC)"); break;
default: break;
}
break;
#if defined(USE_MIDI)
case Track::Note:
type = wxT("midi");
view = wxT("Midi");
break;
#endif
case Track::Label:
type = wxT("label");
view = wxT("Label");
break;
case Track::Time:
type = wxT("time");
view = wxT("Time");
break;
}
cmd += wxString::Format(wxT("(putprop '*TRACK* %d 'INDEX)\n"), ++mTrackIndex);
cmd += wxString::Format(wxT("(putprop '*TRACK* \"%s\" 'NAME)\n"), mCurTrack[0]->GetName().c_str());
cmd += wxString::Format(wxT("(putprop '*TRACK* \"%s\" 'TYPE)\n"), type.c_str());
cmd += wxString::Format(wxT("(putprop '*TRACK* \"%s\" 'VIEW)\n"), view.c_str());
cmd += wxString::Format(wxT("(putprop '*TRACK* %d 'CHANNELS)\n"), mCurNumChannels);
cmd += wxString::Format(wxT("(putprop '*TRACK* (float %g) 'START-TIME)\n"), mCurTrack[0]->GetStartTime());
cmd += wxString::Format(wxT("(putprop '*TRACK* (float %g) 'END-TIME)\n"), mCurTrack[0]->GetEndTime());
cmd += wxString::Format(wxT("(putprop '*TRACK* (float %g) 'GAIN)\n"), mCurTrack[0]->GetGain());
cmd += wxString::Format(wxT("(putprop '*TRACK* (float %g) 'PAN)\n"), mCurTrack[0]->GetPan());
cmd += wxString::Format(wxT("(putprop '*TRACK* (float %g) 'RATE)\n"), mCurTrack[0]->GetRate());
switch (mCurTrack[0]->GetSampleFormat())
{
case int16Sample:
bitFormat = wxT("16");
break;
case int24Sample:
bitFormat = wxT("24");
break;
case floatSample:
bitFormat = wxT("32.0");
break;
}
cmd += wxString::Format(wxT("(putprop '*TRACK* %s 'FORMAT)\n"), bitFormat.c_str());
float maxPeak = 0.0;
wxString clips;
for (int i = 0; i < mCurNumChannels; i++) {
WaveClipArray ca;
mCurTrack[i]->FillSortedClipArray(ca);
for (size_t j = 0; j < ca.GetCount(); j++) {
clips += wxString::Format(wxT("(list (float %g) (float %g))"), ca[j]->GetStartTime(), ca[j]->GetEndTime());
}
float min, max;
mCurTrack[i]->GetMinMax(&min, &max, mT0, mT1);
maxPeak = wxMax(wxMax(fabs(min), fabs(max)), maxPeak);
}
cmd += wxString::Format(wxT("(putprop '*TRACK* (list %s) 'CLIPS)\n"), clips.c_str());
cmd += wxString::Format(wxT("(putprop '*SELECTION* (float %g) 'PEAK-LEVEL)\n"), maxPeak);
}
if (GetEffectFlags() & INSERT_EFFECT) {
nyx_set_audio_params(mCurTrack[0]->GetRate(), 0);
}
else {
nyx_set_audio_params(mCurTrack[0]->GetRate(), mCurLen);
nyx_set_input_audio(StaticGetCallback, (void *)this,
mCurNumChannels,
mCurLen, mCurTrack[0]->GetRate());
}
if (mDebug) {
cmd += wxT("(setf *tracenable* T)\n");
if (mExternal) {
@ -1157,7 +1355,6 @@ void EffectNyquist::OutputCallback(int c)
mDebugOutput += (char)c;
return;
}
std::cout << (char)c;
}
@ -1196,6 +1393,22 @@ void EffectNyquist::OSCallback()
#endif
}
wxArrayString EffectNyquist::GetNyquistSearchPath()
{
wxArrayString audacityPathList = wxGetApp().audacityPathList;
wxArrayString pathList;
for (size_t i = 0; i < audacityPathList.GetCount(); i++)
{
wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH;
wxGetApp().AddUniquePathToPathList(prefix + wxT("nyquist"), pathList);
wxGetApp().AddUniquePathToPathList(prefix + wxT("plugins"), pathList);
wxGetApp().AddUniquePathToPathList(prefix + wxT("plug-ins"), pathList);
}
return pathList;
}
/**********************************************************/
#define ID_NYQ_SLIDER 2000

View File

@ -121,6 +121,8 @@ class AUDACITY_DLL_API EffectNyquist:public Effect
virtual bool SupportsChains();
virtual bool TransferParameters( Shuttle & shuttle );
static wxArrayString GetNyquistSearchPath();
private:
static wxString NyquistToWxString(const char *nyqString);
@ -177,12 +179,14 @@ class AUDACITY_DLL_API EffectNyquist:public Effect
bool mDebug;
std::string mDebugOutput;
int mVersion;
NyqControlArray mControls;
int mCurNumChannels;
WaveTrack *mCurTrack[2];
sampleCount mCurStart[2];
sampleCount mCurLen;
int mTrackIndex;
bool mFirstInGroup;
double mOutputTime;
int mCount;
@ -199,6 +203,8 @@ class AUDACITY_DLL_API EffectNyquist:public Effect
wxArrayString mCategories;
wxString mProps;
friend class NyquistDialog;
};