📄 nyquist.cpp
字号:
/********************************************************************** Audacity: A Digital Audio Editor Nyquist.cpp Dominic Mazzoni**********************************************************************/#include <math.h>#include <locale.h>#include <wx/defs.h>#include <wx/log.h>#include <wx/intl.h>#include <wx/msgdlg.h>#include <wx/textdlg.h>#include <wx/textfile.h>#include "../../Audacity.h"#include "../../AudacityApp.h"#include "../../LabelTrack.h"#include "../../Internat.h"#include "Nyquist.h"#include <locale.h>#include <wx/arrimpl.cpp>WX_DEFINE_OBJARRAY(NyqControlArray);wxString EffectNyquist::mXlispPath;#define NYQ_CTRL_INT 0#define NYQ_CTRL_REAL 1#define NYQ_CTRL_STRING 2extern "C" { extern void set_xlisp_path(const char *p);}#if defined(USE_NYQUIST) && defined(__WXMSW__) && !defined(__CYGWIN__)// Nyquist needs a random function and non-Cygwin MSW doesn't provide one...extern "C" { long random_seed = 1534781L; short random(short lo, short hi) { random_seed *= 13L; random_seed += 1874351L; return((short)(lo + (((hi + 1 - lo) * ((0x00ffff00 & random_seed) >> 8)) >> 16))); }}#endif#define UNINITIALIZED_CONTROL ((double)99999999.99)wxString EffectNyquist::UnQuote(wxString s){ wxString out; int len = s.Length(); if (len>=2 && s.GetChar(0)==wxT('\"') && s.GetChar(len-1)==wxT('\"')) return s.Mid(1, len-2); else return s;}double EffectNyquist::GetCtrlValue(wxString s){ if (s == wxT("rate")) { TrackListIterator iter(mWaveTracks); return ((WaveTrack *)iter.First())->GetRate(); } else { double d; s.ToDouble(&d); return d; }}void EffectNyquist::Parse(wxString line){ wxArrayString tokens; int i; int len = line.Length(); bool sl = false; bool q = false; wxString tok = wxT(""); for(i=1; i<len; i++) { if (line.GetChar(i)==wxT('\\')) sl = true; else if (line.GetChar(i)==wxT('"')) q = !q; else { if (!q && !sl && line.GetChar(i)==wxT(' ') || line.GetChar(i)==wxT('\t')) { tokens.Add(tok); tok = wxT(""); } else if (sl && line.GetChar(i)==wxT('n')) tok += wxT('\n'); else tok += line.GetChar(i); sl = false; } } if (tok != wxT("")) tokens.Add(tok); len = tokens.GetCount(); if (len < 1) return; if (len==2 && tokens[0]==wxT("nyquist") && tokens[1]==wxT("plug-in")) { mOK = true; return; } if (len>=2 && tokens[0]==wxT("type")) { if (tokens[1]==wxT("process")) mFlags = PROCESS_EFFECT | PLUGIN_EFFECT; if (tokens[1]==wxT("generate")) mFlags = INSERT_EFFECT | PLUGIN_EFFECT; if (tokens[1]==wxT("analyze")) mFlags = ANALYZE_EFFECT | PLUGIN_EFFECT; return; } // We support versions 1 and 2 // (Version 2 added support for string parameters.) if (len>=2 && tokens[0]==wxT("version")) { if (tokens[1]==wxT("1") || tokens[1]==wxT("2")) { // We're okay } else { // This is an unsupported plug-in version mOK = false; return; } } if (len>=2 && tokens[0]==wxT("name")) { mName = UnQuote(tokens[1]); return; } if (len>=2 && tokens[0]==wxT("action")) { mAction = UnQuote(tokens[1]); return; } if (len>=2 && tokens[0]==wxT("info")) { mInfo = UnQuote(tokens[1]); return; } if (len>=6 && tokens[0]==wxT("control")) { NyqControl ctrl; ctrl.var = tokens[1]; ctrl.name = tokens[2]; ctrl.label = tokens[4]; ctrl.valStr = tokens[5]; if (tokens[3]==wxT("string")) ctrl.type = NYQ_CTRL_STRING; else { if (len < 8) return; if (tokens[3]==wxT("real")) ctrl.type = NYQ_CTRL_REAL; else ctrl.type = NYQ_CTRL_INT; ctrl.lowStr = tokens[6]; ctrl.highStr = tokens[7]; } ctrl.val = UNINITIALIZED_CONTROL; mControls.Add(ctrl); }}void EffectNyquist::ParseFile(){ wxTextFile f(FILENAME(mFileName.GetFullPath())); if (!f.Open()) return; mCmd = wxT(""); mFlags = PROCESS_EFFECT | PLUGIN_EFFECT; mOK = false; mControls.Clear(); int i; int len = f.GetLineCount(); wxString line; for(i=0; i<len; i++) { line = f[i]; if (line.Length()>1 && line.GetChar(0)==wxT(';')) Parse(line); else mCmd += line + wxT("\n"); }}EffectNyquist::EffectNyquist(wxString fName){ mInteractive = false; mAction = _("Applying Nyquist Effect..."); if (fName == wxT("")) { // Interactive Nyquist mOK = true; mInteractive = true; mCmd = wxT(""); mName = _("Nyquist Prompt..."); mFlags = PROCESS_EFFECT | BUILTIN_EFFECT | ADVANCED_EFFECT; return; } wxLogNull dontLog; mName = wxFileName(fName).GetName(); mFileName = wxFileName(FILENAME(fName)); mFileModified = mFileName.GetModificationTime(); ParseFile();}EffectNyquist::~EffectNyquist(){}bool EffectNyquist::SetXlispPath(){ wxString fname; fname = mXlispPath + wxFILE_SEP_PATH + wxT("nyinit.lsp"); if (!(::wxFileExists(FILENAME(fname)))) mXlispPath = wxT(""); if (mXlispPath == wxT("")) { wxArrayString audacityPathList = wxGetApp().audacityPathList; wxArrayString pathList; wxArrayString files; unsigned int i; for(i=0; i<audacityPathList.GetCount(); i++) { wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH; wxGetApp().AddUniquePathToPathList(prefix + wxT("nyquist"), pathList); } wxGetApp().FindFilesInPathList(wxT("nyquist.lsp"), pathList, wxFILE, files); if (files.GetCount() > 0) { mXlispPath = ::wxPathOnly(files[0]); } } #ifdef _UNICODE /* set_xlisp_path doesn't handle fn_Str() in Unicode build. May or may not actually work. */ set_xlisp_path(mXlispPath.mb_str()); #else // ANSI set_xlisp_path(mXlispPath.fn_str()); #endif // Unicode/ANSI fname = mXlispPath + wxFILE_SEP_PATH + wxT("nyinit.lsp"); return ::wxFileExists(FILENAME(fname));}bool EffectNyquist::PromptUser(){ if (!SetXlispPath()) return false; if (mInteractive) { NyquistInputDialog dlog(mParent, -1, _("Nyquist Prompt"), _("Enter Nyquist Command: "), mCmd); dlog.CentreOnParent(); int result = dlog.ShowModal(); if (result == wxID_CANCEL) return false; if (result == wxID_MORE) mDebug = true; else mDebug = false; mCmd = dlog.GetCommand(); return true; } if (mFileName.GetModificationTime().IsLaterThan(mFileModified)) { ParseFile(); mFileModified = mFileName.GetModificationTime(); } if (mControls.GetCount() == 0) { mDebug = false; return true; } for(unsigned int i=0; i<mControls.GetCount(); i++) { NyqControl *ctrl = &mControls[i]; if (ctrl->type == NYQ_CTRL_STRING) continue; if (ctrl->val == UNINITIALIZED_CONTROL) ctrl->val = GetCtrlValue(ctrl->valStr); ctrl->low = GetCtrlValue(ctrl->lowStr); ctrl->high = GetCtrlValue(ctrl->highStr); if (ctrl->high < ctrl->low) ctrl->high = ctrl->low + 1; if (ctrl->val < ctrl->low) ctrl->val = ctrl->low; if (ctrl->val > ctrl->high) ctrl->val = ctrl->high; ctrl->ticks = 1000; if (ctrl->type==NYQ_CTRL_INT && (ctrl->high - ctrl->low < ctrl->ticks)) ctrl->ticks = (int)(ctrl->high - ctrl->low); } NyquistDialog dlog(mParent, -1, mName, mInfo, &mControls); dlog.CentreOnParent(); int result = dlog.ShowModal(); if (result == wxID_CANCEL) return false; if (result == wxID_MORE) mDebug = true; else mDebug = false; return true;}bool EffectNyquist::Process(){ bool success = true; TrackListIterator iter(mWaveTracks); mCurTrack[0] = (WaveTrack *) iter.First(); mOutputTime = mT1 - mT0; mCount = 0; mProgress = 0; mDebugOutput = wxT(""); while (mCurTrack[0]) { mCurNumChannels = 1; double trackStart = mCurTrack[0]->GetStartTime(); double trackEnd = mCurTrack[0]->GetEndTime(); double t0 = mT0 < trackStart? trackStart: mT0; double t1 = mT1 > trackEnd? trackEnd: mT1; if (t1 >= t0) { if (mCurTrack[0]->GetLinked()) { mCurNumChannels = 2; mCurTrack[1] = (WaveTrack *)iter.Next(); if (mCurTrack[1]->GetRate() != mCurTrack[0]->GetRate()) { wxMessageBox(_("Sorry, cannot apply effect on stereo tracks where the tracks don't match."), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return false; } mCurStart[1] = mCurTrack[1]->TimeToLongSamples(t0); } mCurStart[0] = mCurTrack[0]->TimeToLongSamples(t0); longSampleCount end = mCurTrack[0]->TimeToLongSamples(t1); mCurLen = (sampleCount)(end - mCurStart[0]); success = ProcessOne(); if (!success) goto finish; } mCurTrack[0] = (WaveTrack *) iter.Next(); mCount += mCurNumChannels; } mT1 = mT0 + mOutputTime; finish: if (mDebug) { NyquistOutputDialog dlog(mParent, -1, _("Nyquist"), _("Nyquist Output: "), mDebugOutput); dlog.CentreOnParent(); dlog.ShowModal(); } return success;}int EffectNyquist::GetCallback(float *buffer, int ch, long start, long len){ if (mCurBuffer[ch]) { if ((mCurStart[ch] + start) < mCurBufferStart[ch] || (mCurStart[ch] + start)+len > mCurBufferStart[ch]+mCurBufferLen[ch]) { delete[] mCurBuffer[ch]; mCurBuffer[ch] = NULL; } } if (!mCurBuffer[ch]) { mCurBufferStart[ch] = (mCurStart[ch] + start); mCurBufferLen[ch] = mCurTrack[ch]->GetBestBlockSize(mCurBufferStart[ch]); if (mCurBufferLen[ch] < len) mCurBufferLen[ch] = mCurTrack[ch]->GetIdealBlockSize(); if (mCurBufferStart[ch] + mCurBufferLen[ch] > mCurStart[ch] + mCurLen) mCurBufferLen[ch] = mCurStart[ch] + mCurLen - mCurBufferStart[ch]; mCurBuffer[ch] = NewSamples(mCurBufferLen[ch], floatSample); if (!mCurTrack[ch]->Get(mCurBuffer[ch], floatSample, mCurBufferStart[ch], mCurBufferLen[ch])) { wxPrintf(wxT("GET error\n")); return -1; } } long offset = (mCurStart[ch] + start) - mCurBufferStart[ch]; CopySamples(mCurBuffer[ch] + offset*SAMPLE_SIZE(floatSample), floatSample, (samplePtr)buffer, floatSample, len); if (ch==0) { double progress = 1.0*(start+len)/mCurLen; if (progress > mProgress) mProgress = progress; if (TotalProgress(mProgress)) return -1; } return 0;}int EffectNyquist::PutCallback(float *buffer, int channel, long start, long len){ if (mOutputTrack[channel]->Append((samplePtr)buffer, floatSample, len)) return 0; // success else return -1; // failure}int EffectNyquist::StaticGetCallback(float *buffer, int channel, long start, long len, void *userdata){ EffectNyquist *This = (EffectNyquist *)userdata; return This->GetCallback(buffer, channel, start, len);}int EffectNyquist::StaticPutCallback(float *buffer, int channel, long start, long len, void *userdata){ EffectNyquist *This = (EffectNyquist *)userdata; return This->PutCallback(buffer, channel, start, len);}bool EffectNyquist::ProcessOne(){ // libnyquist breaks except in LC_NUMERIC=="C". // // MB: setlocale is not thread-safe. Should use uselocale() // if available, or fix libnyquist to be locale-independent. setlocale(LC_NUMERIC, "C"); nyx_rval rval; nyx_init(); if (mDebug)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -