35#include "nyquist/xlisp/xlisp.h"
42#include <wx/numformatter.h>
43#include <wx/sstream.h>
44#include <wx/tokenzr.h>
45#include <wx/txtstrm.h>
46#include <wx/wfstream.h>
51#define NYQ_MAX_LEN (std::numeric_limits<int64_t>::max())
59 mAction =
XO(
"Applying Nyquist Effect...");
142 return XO(
"Audacity");
170 for (
size_t i = 0, cnt = paths.size(); i < cnt; i++)
172 fileName = wxFileName(paths[i] +
wxT(
"/") +
mHelpFile).GetFullPath();
173 if (wxFileExists(fileName))
175 return {
true, fileName };
178 return {
false, wxEmptyString };
266 d,
static_cast<const wxChar*
>(ctrl.var.c_str()), (
double)0.0,
267 ctrl.low, ctrl.high, 1.0);
272 x,
static_cast<const wxChar*
>(ctrl.var.c_str()), 0,
273 static_cast<int>(ctrl.low),
static_cast<int>(ctrl.high), 1);
282 x,
static_cast<const wxChar*
>(ctrl.var.c_str()), 0,
283 ctrl.choices.data(), ctrl.choices.size());
288 ctrl.valStr, ctrl.var, wxString {}, ctrl.lowStr, ctrl.highStr);
306 for (
size_t c = 0, cnt =
mControls.size(); c < cnt; c++)
320 parms.Write(ctrl.
var, d);
324 parms.Write(ctrl.
var, (
int)d);
374 pParms = &localParms;
394 const auto kTestOnly =
true;
395 const auto kTestAndSet =
false;
426 for (
size_t c = 0, cnt =
mControls.size(); c < cnt; c++)
450 parms.Read(ctrl.
var, &val) && val >= ctrl.
low && val <= ctrl.
high;
451 if (good && !bTestOnly)
458 parms.Read(ctrl.
var, &val) && val >= ctrl.
low && val <= ctrl.
high;
459 if (good && !bTestOnly)
460 ctrl.
val = (double)val;
469 if (good && !bTestOnly)
470 ctrl.
val = (double)val;
475 good = parms.Read(ctrl.
var, &val);
476 if (good && !bTestOnly)
485 badCount += !good ? 1 : 0;
521 bool bAllowSpectralEditing =
false;
522 bool hasSpectral =
false;
528 hasSpectral |= displays.end() !=
530 displays.begin(), displays.end(),
532 WaveChannelViewConstants::Spectrum, {} });
538 bAllowSpectralEditing =
true;
543 if (!bAllowSpectralEditing || ((
mF0 < 0.0) && (
mF1 < 0.0)))
548 XO(
"Enable track spectrogram view before\n"
549 "applying 'Spectral' effects."),
553 XO(
"To use 'Spectral effects', enable 'Spectral Selection'\n"
554 "in the track Spectrogram settings and select the\n"
555 "frequency range for the effect to act von."),
562 if (!mIsPrompt && !mExternal)
574 if (mFileName.GetModificationTime().IsLaterThan(mFileModified))
578 auto dummySettings = MakeSettings();
579 constexpr auto key = L
"TemporarySettings";
580 SaveUserPreset(
key, dummySettings);
584 mFileModified = mFileName.GetModificationTime();
587 (void)LoadUserPreset(
key, dummySettings);
610 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen);
612 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen);
614 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen,
617 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen,
649 auto cleanup =
finally([&] {
651 nyquistSettings.proxySettings = {};
655 proxy.mDebug = nyquistSettings.proxyDebug;
656 proxy.mControls = move(nyquistSettings.controls);
657 auto result =
Delegate(proxy, nyquistSettings.proxySettings);
709 std::optional<EffectOutputTracks> oOutputs;
724 XO(
"error: File \"%s\" specified in header but not found in plug-in path.\n")
734 mProps += wxString::Format(
735 wxT(
"(putprop '*AUDACITY* (list %d %d %d) 'VERSION)\n"),
736 AUDACITY_VERSION, AUDACITY_RELEASE, AUDACITY_REVISION);
742 mProps += wxString::Format(
743 wxT(
"(putprop '*AUDACITY* \"%s\" 'LANGUAGE)\n"), lang);
745 mProps += wxString::Format(
746 wxT(
"(setf *DECIMAL-SEPARATOR* #\\%c)\n"),
747 wxNumberFormatter::GetDecimalSeparator());
749 mProps += wxString::Format(
750 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'BASE)\n"),
752 mProps += wxString::Format(
753 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'DATA)\n"),
755 mProps += wxString::Format(
756 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'HELP)\n"),
758 mProps += wxString::Format(
759 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'TEMP)\n"),
761 mProps += wxString::Format(
762 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'SYS-TEMP)\n"),
764 mProps += wxString::Format(
765 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'DOCUMENTS)\n"),
767 mProps += wxString::Format(
768 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'HOME)\n"),
773 for (
size_t i = 0, cnt = paths.size(); i < cnt; i++)
777 list = list.RemoveLast();
779 mProps += wxString::Format(
780 wxT(
"(putprop '*SYSTEM-DIR* (list %s) 'PLUGIN)\n"), list);
781 mProps += wxString::Format(
782 wxT(
"(putprop '*SYSTEM-DIR* (list %s) 'PLUG-IN)\n"), list);
783 mProps += wxString::Format(
784 wxT(
"(putprop '*SYSTEM-DIR* \"%s\" 'USER-PLUG-IN)\n"),
788 wxDateTime now = wxDateTime::Now();
789 int year = now.GetYear();
790 int doy = now.GetDayOfYear();
791 int dom = now.GetDay();
793 wxDateTime::Month month = now.GetMonth();
794 wxDateTime::WeekDay day = now.GetWeekDay();
797 mProps += wxString::Format(
798 wxT(
"(setf *SYSTEM-TIME* (list %d %d %d %d %d))\n"), year, doy,
799 now.GetHour(), now.GetMinute(), now.GetSecond());
801 mProps += wxString::Format(
802 wxT(
"(putprop '*SYSTEM-TIME* \"%s\" 'DATE)\n"), now.FormatDate());
803 mProps += wxString::Format(
804 wxT(
"(putprop '*SYSTEM-TIME* \"%s\" 'TIME)\n"), now.FormatTime());
805 mProps += wxString::Format(
806 wxT(
"(putprop '*SYSTEM-TIME* \"%s\" 'ISO-DATE)\n"),
807 now.FormatISODate());
808 mProps += wxString::Format(
809 wxT(
"(putprop '*SYSTEM-TIME* \"%s\" 'ISO-TIME)\n"),
810 now.FormatISOTime());
812 wxString::Format(
wxT(
"(putprop '*SYSTEM-TIME* %d 'YEAR)\n"), year);
813 mProps += wxString::Format(
814 wxT(
"(putprop '*SYSTEM-TIME* %d 'DAY)\n"), dom);
816 wxString::Format(
wxT(
"(putprop '*SYSTEM-TIME* %d 'MONTH)\n"), month);
817 mProps += wxString::Format(
818 wxT(
"(putprop '*SYSTEM-TIME* \"%s\" 'MONTH-NAME)\n"),
819 now.GetMonthName(month));
820 mProps += wxString::Format(
821 wxT(
"(putprop '*SYSTEM-TIME* \"%s\" 'DAY-NAME)\n"),
822 now.GetWeekDayName(day));
824 mProps += wxString::Format(
825 wxT(
"(putprop '*PROJECT* %d 'PROJECTS)\n"),
827 mProps += wxString::Format(
828 wxT(
"(putprop '*PROJECT* \"%s\" 'NAME)\n"),
836 wxString waveTrackList;
840 for (
auto t : countRange)
844 if (t->GetSelected())
845 waveTrackList += wxString::Format(
wxT(
"%d "), 1 + numTracks);
860 mProps += wxString::Format(
861 wxT(
"(putprop '*PROJECT* (float %s) 'RATE)\n"),
864 wxString::Format(
wxT(
"(putprop '*PROJECT* %d 'TRACKS)\n"), numTracks);
865 mProps += wxString::Format(
866 wxT(
"(putprop '*PROJECT* %d 'WAVETRACKS)\n"), numWave);
867 mProps += wxString::Format(
868 wxT(
"(putprop '*PROJECT* %d 'LABELTRACKS)\n"), numLabel);
869 mProps += wxString::Format(
870 wxT(
"(putprop '*PROJECT* %d 'MIDITRACKS)\n"), numMidi);
871 mProps += wxString::Format(
872 wxT(
"(putprop '*PROJECT* %d 'TIMETRACKS)\n"), numTime);
874 double previewLen = 6.0;
875 gPrefs->
Read(
wxT(
"/AudioIO/EffectsPreviewLen"), &previewLen);
876 mProps += wxString::Format(
877 wxT(
"(putprop '*PROJECT* (float %s) 'PREVIEW-DURATION)\n"),
882 mProps += wxString::Format(
wxT(
"(setf *PREVIEWP* %s)\n"), isPreviewing);
884 mProps += wxString::Format(
885 wxT(
"(putprop '*SELECTION* (list %s) 'TRACKS)\n"), waveTrackList);
886 mProps += wxString::Format(
893 auto message =
XO(
"Audio selection required.");
899 std::optional<TrackIterRange<WaveTrack>> pRange;
901 pRange.emplace(oOutputs->Get().Selected<
WaveTrack>());
907 Track* gtLast = NULL;
908 double progressTot {};
910 for (; bOnePassTool || pRange->first != pRange->second;
911 (void)(!pRange || (++pRange->first,
true)))
919 [
this](
double frac) {
return TotalProgress(frac); }, scale, progressTot
921 auto& mCurNumChannels = nyxContext.mCurNumChannels;
922 auto& mCurChannelGroup = nyxContext.mCurChannelGroup;
923 auto& mCurTrack = nyxContext.mCurTrack;
924 auto& mCurStart = nyxContext.mCurStart;
925 auto& mCurLen = nyxContext.mCurLen;
927 mCurChannelGroup = pRange ? *pRange->first :
nullptr;
928 mCurTrack[0] = mCurChannelGroup ?
929 (*mCurChannelGroup->Channels().begin()).get() :
932 assert(mCurChannelGroup !=
nullptr || bOnePassTool);
933 if ((
mT1 >=
mT0) || bOnePassTool)
940 if (
auto channels = mCurChannelGroup->Channels();
948 mCurTrack[1] = (*++channels.first).get();
956 mCurStart = mCurChannelGroup->TimeToLongSamples(
mT0);
957 auto end = mCurChannelGroup->TimeToLongSamples(
mT1);
958 mCurLen =
end - mCurStart;
974 wxString prevlocale = wxSetlocale(LC_NUMERIC, NULL);
975 wxSetlocale(LC_NUMERIC, wxString(
wxT(
"C")));
981 auto cleanup =
finally([&] {
982 nyx_capture_output(NULL, (
void*)NULL);
983 nyx_set_os_callback(NULL, (
void*)NULL);
990 wxString lowHz =
wxT(
"nil");
991 wxString highHz =
wxT(
"nil");
992 wxString centerHz =
wxT(
"nil");
993 wxString bandwidth =
wxT(
"nil");
1005 if ((
mF0 >= 0.0) && (
mF1 >= 0.0))
1015 double bw = log(
mF1 /
mF0) / log(2.0);
1016 if (!std::isinf(bw))
1023 wxT(
"(putprop '*SELECTION* %s 'LOW-HZ)\n"), lowHz);
1025 wxT(
"(putprop '*SELECTION* %s 'CENTER-HZ)\n"), centerHz);
1027 wxT(
"(putprop '*SELECTION* %s 'HIGH-HZ)\n"), highHz);
1029 wxT(
"(putprop '*SELECTION* %s 'BANDWIDTH)\n"), bandwidth);
1032 mCurChannelGroup ? mCurChannelGroup->SnapToSample(
mT0) :
mT0;
1034 mCurChannelGroup ? mCurChannelGroup->SnapToSample(
mT1) :
mT1;
1036 wxT(
"(putprop '*SELECTION* (float %s) 'START)\n"),
1039 wxT(
"(putprop '*SELECTION* (float %s) 'END)\n"),
1043 success =
ProcessOne(nyxContext, oOutputs ? &*oOutputs :
nullptr);
1046 wxSetlocale(LC_NUMERIC, prevlocale);
1048 if (!success || bOnePassTool)
1052 progressTot += nyxContext.mProgressIn + nyxContext.mProgressOut;
1055 mCount += mCurNumChannels;
1085 mT0 = selectedRegion.t0();
1086 mT1 = selectedRegion.t1();
1106 const auto wt =
dynamic_cast<const WaveTrack*
>(t);
1113 for (
size_t i = 0, n = ca.size(); i < n; ++i)
1117 clips += wxString::Format(
1118 wxT(
"(list (float %s) (float %s))"),
1146 cmd +=
wxT(
"(snd-set-latency 0.1)");
1151 cmd +=
wxT(
"(setf S 0.25)\n");
1154 nyx_set_audio_name(
"*TRACK*");
1155 cmd +=
wxT(
"(setf S 0.25)\n");
1159 nyx_set_audio_name(
"S");
1160 cmd +=
wxT(
"(setf *TRACK* '*unbound*)\n");
1177 wxString spectralEditp;
1190 const auto format = [&](
decltype(displays[0]) display) {
1193 return wxString::Format(
1194 wxT(
"\"%s\""), display.name.Stripped().Debug());
1196 if (displays.empty())
1198 else if (displays.size() == 1)
1199 view =
format(displays[0]);
1202 view =
wxT(
"(list");
1203 for (
auto display : displays)
1204 view += wxString(
wxT(
" ")) +
format(display);
1208#if defined(USE_MIDI)
1211 view =
wxT(
"\"Midi\"");
1215 type =
wxT(
"label");
1216 view =
wxT(
"\"Label\"");
1220 view =
wxT(
"\"Time\"");
1224 wxString::Format(
wxT(
"(putprop '*TRACK* %d 'INDEX)\n"), ++
mTrackIndex);
1225 cmd += wxString::Format(
1226 wxT(
"(putprop '*TRACK* \"%s\" 'NAME)\n"),
1228 cmd += wxString::Format(
wxT(
"(putprop '*TRACK* \"%s\" 'TYPE)\n"), type);
1231 cmd += wxString::Format(
wxT(
"(putprop '*TRACK* %s 'VIEW)\n"), view);
1232 cmd += wxString::Format(
1233 wxT(
"(putprop '*TRACK* %d 'CHANNELS)\n"), mCurNumChannels);
1237 cmd += wxString::Format(
1238 wxT(
"(putprop '*TRACK* %s 'SPECTRAL-EDIT-ENABLED)\n"), spectralEditp);
1240 const double startTime = mCurChannelGroup->GetStartTime();
1241 const double endTime = mCurChannelGroup->GetEndTime();
1243 cmd += wxString::Format(
1244 wxT(
"(putprop '*TRACK* (float %s) 'START-TIME)\n"),
1246 cmd += wxString::Format(
1247 wxT(
"(putprop '*TRACK* (float %s) 'END-TIME)\n"),
1249 cmd += wxString::Format(
1251 "(putprop '*TRACK* (float %s) 'GAIN)\n"),
1257 cmd += wxString::Format(
1258 wxT(
"(putprop '*TRACK* (float %s) 'PAN)\n"),
1260 cmd += wxString::Format(
1261 wxT(
"(putprop '*TRACK* (float %s) 'RATE)\n"),
1264 switch (mCurChannelGroup->GetSampleFormat())
1267 bitFormat =
wxT(
"16");
1270 bitFormat =
wxT(
"24");
1273 bitFormat =
wxT(
"32.0");
1277 wxString::Format(
wxT(
"(putprop '*TRACK* %s 'FORMAT)\n"), bitFormat);
1279 float maxPeakLevel = 0.0;
1283 wxString inClips, outClips, peakString, rmsString;
1285 for (
size_t i = 0; i < mCurNumChannels; i++)
1287 float maxPeak = 0.0;
1288 if (mCurNumChannels > 1)
1290 inClips +=
wxT(
"(list ");
1291 outClips +=
wxT(
"(list ");
1293 inClips += inClipBoundaries;
1294 outClips += outClipBoundaries;
1295 if (mCurNumChannels > 1)
1297 inClips +=
wxT(
" )");
1298 outClips +=
wxT(
" )");
1302 *mCurTrack[i],
mT0,
mT1);
1303 min = pair.first, max = pair.second;
1304 maxPeak = std::max(std::max(fabs(
min), fabs(max)), maxPeak);
1305 maxPeakLevel = std::max(maxPeakLevel, maxPeak);
1309 !std::isinf(maxPeak) && !std::isnan(maxPeak) && (maxPeak < FLT_MAX))
1311 peakString += wxString::Format(
1316 peakString +=
wxT(
"nil ");
1321 if (!std::isinf(rms) && !std::isnan(rms))
1328 rmsString +=
wxT(
"NIL ");
1332 cmd += wxString::Format(
1333 wxT(
"(putprop '*TRACK* %s%s ) 'INCLIPS)\n"),
1334 (mCurNumChannels == 1) ?
wxT(
"(list ") :
wxT(
"(vector "), inClips);
1335 cmd += wxString::Format(
1336 wxT(
"(putprop '*TRACK* %s%s ) 'CLIPS)\n"),
1337 (mCurNumChannels == 1) ?
wxT(
"(list ") :
wxT(
"(vector "), outClips);
1339 (mCurNumChannels > 1) ?
1340 cmd += wxString::Format(
1341 wxT(
"(putprop '*SELECTION* (vector %s) 'PEAK)\n"), peakString) :
1343 wxString::Format(
wxT(
"(putprop '*SELECTION* %s 'PEAK)\n"), peakString);
1346 !std::isinf(maxPeakLevel) && !std::isnan(maxPeakLevel) &&
1347 (maxPeakLevel < FLT_MAX))
1349 cmd += wxString::Format(
1350 wxT(
"(putprop '*SELECTION* (float %s) 'PEAK-LEVEL)\n"),
1354 (mCurNumChannels > 1) ?
1355 cmd += wxString::Format(
1356 wxT(
"(putprop '*SELECTION* (vector %s) 'RMS)\n"), rmsString) :
1358 wxString::Format(
wxT(
"(putprop '*SELECTION* %s 'RMS)\n"), rmsString);
1363 nyx_set_audio_params(44100, 0);
1365 nyx_set_audio_params(mCurChannelGroup->GetRate(), 0);
1369 nyx_set_audio_params(mCurChannelGroup->GetRate(), curLen);
1370 nyx_set_input_audio(
1372 curLen, mCurChannelGroup->GetRate());
1379 cmd +=
wxT(
"(setf s 0.25)\n");
1384 cmd +=
wxT(
"(setf *tracenable* T)\n");
1387 cmd +=
wxT(
"(setf *breakenable* T)\n");
1395 cmd +=
wxT(
"(setf *tracenable* NIL)\n");
1398 for (
unsigned int j = 0; j <
mControls.size(); j++)
1409 cmd += wxString::Format(
1418 cmd += wxString::Format(
1425 cmd +=
wxT(
"(setf ");
1431 cmd +=
wxT(
"\")\n");
1443 str +=
wxT(
"\nset aud:result = main()\n");
1450 cmd +=
wxT(
"(setf *tracenable* nil)\n");
1451 cmd +=
wxT(
"(setf *breakenable* nil)\n");
1452 cmd +=
wxT(
"(setf *sal-traceback* t)\n");
1457 cmd +=
wxT(
"(setf *sal-compiler-debug* t)\n");
1460 cmd +=
wxT(
"(setf *sal-call-stack* nil)\n");
1464 cmd +=
wxT(
"(setf aud:result nil)\n");
1465 cmd +=
wxT(
"(sal-compile-audacity \"") +
str +
wxT(
"\" t t nil)\n");
1469 cmd +=
wxT(
"(prog1 aud:result (setf aud:result nil))\n");
1478 rval = nyx_eval_expression(cmd.mb_str(wxConvUTF8));
1493 (rval != nyx_audio) &&
1496 if (mCurNumChannels == 1)
1511 XO(
"';type tool' effects cannot return audio from Nyquist.\n") +
1521 XO(
"';type tool' effects cannot return labels from Nyquist.\n") +
1526 if (rval == nyx_error)
1546 if (rval == nyx_list)
1548 wxLogMessage(
"Nyquist returned nyx_list");
1560 if (rval == nyx_string)
1590 if (rval == nyx_double)
1592 auto str =
XO(
"Nyquist returned the value: %f").Format(nyx_get_double());
1597 if (rval == nyx_int)
1599 auto str =
XO(
"Nyquist returned the value: %d").Format(nyx_get_int());
1604 if (rval == nyx_labels)
1612 unsigned int numLabels = nyx_get_num_labels();
1617 auto newTrack = std::make_shared<LabelTrack>();
1626 for (l = 0; l < numLabels; l++)
1633 nyx_get_label(l, &t0, &t1, &
str);
1640 wxASSERT(rval == nyx_audio);
1642 int outChannels = nyx_get_audio_num_channels();
1643 if (outChannels > (
int)mCurNumChannels)
1646 XO(
"Nyquist returned too many audio channels.\n"));
1650 if (outChannels == -1)
1653 XO(
"Nyquist returned one audio channel as an array.\n"));
1657 if (outChannels == 0)
1663 nyxContext.
mOutputTrack = mCurChannelGroup->EmptyCopy();
1671 std::rethrow_exception(pException);
1684 if (outChannels <
static_cast<int>(mCurNumChannels))
1691 tempTrack = out->MonoToStereo();
1704 (out->TimeToLongSamples(
mT0) +
1706 out->TimeToLongSamples(
mT1)) :
1709 mCurChannelGroup->ClearAndPaste(
1718 t->SyncLockAdjust(
mT1,
mT0 + out->GetEndTime());
1734 wxString
str(nyqString, wxConvUTF8);
1735 if (nyqString != NULL && nyqString[0] &&
str.empty())
1739 "[Warning: Nyquist returned invalid UTF-8 string, converted here as Latin-1]");
1749 wxString
str = inStr;
1759 std::vector<EnumValueSymbol> results;
1760 if (text[0] ==
wxT(
'('))
1765 auto& choices = tzer.
tokens;
1767 for (
auto& choice : choices)
1781 auto choices = wxStringTokenize(
1782 text[0] ==
wxT(
'"') ? text.Mid(1, text.length() - 2) : text,
wxT(
","));
1783 for (
auto& choice : choices)
1784 results.push_back({ choice.Trim(
true).Trim(
false) });
1793 if (text[0] ==
wxT(
'('))
1797 for (
const auto& token : tzer.
tokens)
1798 results.push_back(
UnQuote(token));
1807 if (text[0] ==
wxT(
'('))
1811 auto& tokens = tzer.
tokens;
1812 if (tokens.size() == 2)
1822 if (text[0] ==
wxT(
'('))
1826 auto& types = tzer.
tokens;
1827 if (!types.empty() && types[0][0] ==
wxT(
'('))
1828 for (
auto& type : types)
1831 if (results.empty())
1836 auto pieces = wxSplit(
str,
'|');
1838 auto size = pieces.size();
1840 --
size, pieces.pop_back();
1841 for (
size_t ii = 0; ii <
size; ii += 2)
1844 auto extensionStrings = wxSplit(pieces[ii + 1],
';');
1845 for (
const auto& extensionString : extensionStrings)
1846 if (extensionString.StartsWith(
wxT(
"*.")))
1848 auto ext = extensionString.substr(2);
1849 if (ext ==
wxT(
"*"))
1852 extensions.push_back(ext);
1854 results.push_back({
Verbatim(pieces[ii]), extensions });
1891 const wxString& s,
bool allowParens, wxString* pExtraString)
1894 *pExtraString = wxString {};
1896 int len = s.length();
1897 if (len >= 2 && s[0] ==
wxT(
'\"') && s[len - 1] ==
wxT(
'\"'))
1899 auto unquoted = s.Mid(1, len - 2);
1905 allowParens && len >= 2 && s[0] ==
wxT(
'(') && s[len - 1] ==
wxT(
')'))
1909 auto& tokens = tzer.
tokens;
1910 if (tokens.size() > 1)
1912 if (pExtraString && tokens[1][0] ==
'(')
1917 *pExtraString =
UnQuote(tokens[0],
false);
1937 const wxString& s,
bool allowParens, wxString* pExtraString)
1961 const wxString& line,
bool eof,
size_t trimStart,
size_t trimEnd)
1963 auto endToken = [&] {
1974 if (
q && !
sl && c ==
wxT(
'\\'))
1981 if (!
sl && c ==
wxT(
'"'))
2004 else if (!
q && !
paren && (c ==
wxT(
' ') || c ==
wxT(
'\t')))
2008 else if (!
q && c ==
wxT(
';'))
2014 else if (!
q && c ==
wxT(
'('))
2019 endToken(),
tok += c;
2024 else if (!
q && c ==
wxT(
')'))
2029 tok += c, endToken();
2032 paren = 0, endToken();
2054 if (eof || (!
q && !
paren))
2070 Tokenizer& tzer,
const wxString& line,
bool eof,
bool first)
2072 if (!tzer.
Tokenize(line, eof, first ? 1 : 0, 0))
2075 const auto& tokens = tzer.
tokens;
2076 int len = tokens.size();
2085 len == 2 && tokens[0] ==
wxT(
"nyquist") &&
2086 (tokens[1] ==
wxT(
"plug-in") || tokens[1] ==
wxT(
"plugin")))
2092 if (len >= 2 && tokens[0] ==
wxT(
"type"))
2094 wxString tok = tokens[1];
2096 if (tok ==
wxT(
"tool"))
2111 if (tok ==
wxT(
"process"))
2115 else if (tok ==
wxT(
"generate"))
2119 else if (tok ==
wxT(
"analyze"))
2124 if (len >= 3 && tokens[2] ==
wxT(
"spectral"))
2132 if (len == 2 && tokens[0] ==
wxT(
"codetype"))
2135 if (tokens[1] ==
wxT(
"lisp"))
2140 else if (tokens[1] ==
wxT(
"sal"))
2148 if (len >= 2 && tokens[0] ==
wxT(
"debugflags"))
2150 for (
int i = 1; i < len; i++)
2154 if (tokens[i] ==
wxT(
"trace"))
2158 else if (tokens[i] ==
wxT(
"notrace"))
2162 else if (tokens[i] ==
wxT(
"compiler"))
2166 else if (tokens[i] ==
wxT(
"nocompiler"))
2178 if (len >= 2 && tokens[0] ==
wxT(
"version"))
2181 tokens[1].ToLong(&v);
2187 XO(
"This version of Audacity does not support Nyquist plug-in version %ld")
2194 if (len >= 2 && tokens[0] ==
wxT(
"name"))
2205 if (
name.EndsWith(
wxT(
"...")))
2211 if (len >= 2 && tokens[0] ==
wxT(
"action"))
2217 if (len >= 2 && tokens[0] ==
wxT(
"info"))
2223 if (len >= 2 && tokens[0] ==
wxT(
"preview"))
2225 if (tokens[1] ==
wxT(
"enabled") || tokens[1] ==
wxT(
"true"))
2230 else if (tokens[1] ==
wxT(
"linear"))
2235 else if (tokens[1] ==
wxT(
"selection"))
2240 else if (tokens[1] ==
wxT(
"disabled") || tokens[1] ==
wxT(
"false"))
2249 if (len >= 2 && tokens[0] ==
wxT(
"maxlen"))
2252 tokens[1].ToLongLong(&v);
2256 if (len >= 2 && tokens[0] ==
wxT(
"mergeclips"))
2260 tokens[1].ToLong(&v);
2265 if (len >= 2 && tokens[0] ==
wxT(
"restoresplits"))
2269 tokens[1].ToLong(&v);
2274 if (len >= 2 && tokens[0] ==
wxT(
"author"))
2280 if (len >= 2 && tokens[0] ==
wxT(
"release"))
2287 if (len >= 2 && tokens[0] ==
wxT(
"copyright"))
2294 if (len >= 2 && tokens[0] ==
wxT(
"manpage"))
2302 if (len >= 2 && tokens[0] ==
wxT(
"helpfile"))
2310 if (len >= 2 && tokens[0] ==
wxT(
"debugbutton"))
2312 if (tokens[1] ==
wxT(
"disabled") || tokens[1] ==
wxT(
"false"))
2319 if (len >= 3 && tokens[0] ==
wxT(
"control"))
2323 if (len == 3 && tokens[1] ==
wxT(
"text"))
2325 ctrl.
var = tokens[1];
2331 ctrl.
var = tokens[1];
2334 ctrl.
label = tokens[4];
2337 ctrl.
valStr = len > 5 ? tokens[5] : wxString {};
2340 ctrl.
valStr.length() > 0 &&
2347 if (tokens[3] ==
wxT(
"string"))
2352 else if (tokens[3] ==
wxT(
"choice"))
2358 else if (tokens[3] ==
wxT(
"file"))
2376 (tokens[3] ==
wxT(
"float")) ||
2377 (tokens[3] ==
wxT(
"real")))
2379 else if (tokens[3] ==
wxT(
"int"))
2381 else if (tokens[3] ==
wxT(
"float-text"))
2383 else if (tokens[3] ==
wxT(
"int-text"))
2385 else if (tokens[3] ==
wxT(
"time"))
2392 "Bad Nyquist 'control' type specification: '%s' in plug-in file '%s'.\nControl not created."),
2411 ctrl.
lowStr.IsSameAs(
wxT(
"nil"),
false))
2417 ctrl.
lowStr.IsSameAs(
wxT(
"nil"),
false))
2419 ctrl.
low = -(FLT_MAX);
2423 ctrl.
lowStr.IsSameAs(
wxT(
"nil"),
false))
2437 ctrl.
high = INT_MAX;
2444 ctrl.
high = FLT_MAX;
2482 if (len >= 2 && tokens[0] ==
wxT(
"categories"))
2484 for (
size_t i = 1; i < tokens.size(); ++i)
2500 wxTextInputStream pgm(stream,
wxT(
" \t"), wxConvAuto());
2524 while (!stream.Eof() && stream.IsOk())
2526 wxString line = pgm.ReadLine();
2528 line.length() > 1 &&
2532 (line[0] ==
wxT(
';') || line[0] ==
wxT(
'$')))
2535 unsigned nLines = 1;
2538 bool control = line[0] ==
wxT(
'$') || line.StartsWith(
wxT(
";control"));
2540 done =
Parse(tzer, line, !control || stream.Eof(), nLines == 1);
2541 while (!done && (line = pgm.ReadLine(), ++nLines,
true));
2554 line[0] ==
wxT(
'(') ||
2555 (line[0] ==
wxT(
'#') && line.length() > 1 &&
2556 line[1] ==
wxT(
'|')))
2561 else if (line.Upper().Find(
wxT(
"RETURN")) != wxNOT_FOUND)
2576 XO(
"Your code looks like SAL syntax, but there is no \'return\' statement.\n\
2577For SAL, use a return statement such as:\n\treturn *track* * 0.1\n\
2578or for LISP, begin with an open parenthesis such as:\n\t(mult *track* 0.1)\n ."),
2595 wxFileInputStream rawStream(
mFileName.GetFullPath());
2596 wxBufferedInputStream stream(rawStream, 10000);
2603 wxStringInputStream stream(cmd +
wxT(
" "));
2609 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen,
2612 auto This =
static_cast<NyxContext*
>(userdata);
2613 return This->
GetCallback(buffer, channel, start, len, totlen);
2617 float* buffer,
int ch, int64_t start, int64_t len, int64_t)
2622 (mCurStart + start) < mCurBufferStart[ch] ||
2623 (mCurStart + start) + len > mCurBufferStart[ch] + mCurBufferLen[ch])
2625 mCurBuffer[ch].reset();
2629 if (!mCurBuffer[ch])
2631 mCurBufferStart[ch] = (mCurStart + start);
2632 mCurBufferLen[ch] = mCurTrack[ch]->GetBestBlockSize(mCurBufferStart[ch]);
2634 if (mCurBufferLen[ch] < (
size_t)len)
2635 mCurBufferLen[ch] = mCurTrack[ch]->GetIdealBlockSize();
2638 mCurBufferLen[ch], mCurStart + mCurLen - mCurBufferStart[ch]);
2642 mCurBuffer[ch] =
Buffer {
safenew float[mCurBufferLen[ch]] };
2645 mCurTrack[ch]->GetFloats(
2646 mCurBuffer[ch].get(), mCurBufferStart[ch], mCurBufferLen[ch]);
2651 mpException = std::current_exception();
2658 auto offset = (mCurStart + start - mCurBufferStart[ch]).as_size_t();
2659 const void* src = &mCurBuffer[ch][offset];
2660 std::memcpy(buffer, src, len *
sizeof(
float));
2664 double progress = mScale * ((start + len) / mCurLen.as_double());
2665 if (progress > mProgressIn)
2666 mProgressIn = progress;
2667 if (mProgressReport(mProgressIn + mProgressOut + mProgressTot))
2675 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen,
2678 auto This =
static_cast<NyxContext*
>(userdata);
2679 return This->
PutCallback(buffer, channel, start, len, totlen);
2683 float* buffer,
int channel, int64_t start, int64_t len, int64_t totlen)
2686 return GuardedCall<int>(
2690 double progress = mScale * ((float)(start + len) / totlen);
2691 if (progress > mProgressOut)
2692 mProgressOut = progress;
2693 if (mProgressReport(mProgressIn + mProgressOut + mProgressTot))
2697 auto iChannel = mOutputTrack->Channels().begin();
2721 std::cout << (char)c;
2755 for (
size_t i = 0; i < audacityPathList.size(); i++)
2757 wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH;
2782#if defined(__WXMSW__)
2783 path.Replace(
"/", wxFileName::GetPathSeparator());
2786 path.Trim(
true).Trim(
false);
2788 typedef std::unordered_map<wxString, FilePath> map;
2798 int characters = path.Find(wxFileName::GetPathSeparator());
2799 if (characters == wxNOT_FOUND)
2804 if (pathKeys.find(path) != pathKeys.end())
2807 path = pathKeys[path] + wxFileName::GetPathSeparator();
2811 path = pathKeys[
"*default*"] + wxFileName::GetPathSeparator() + path;
2816 wxString firstDir = path.Left(characters);
2817 wxString rest = path.Mid(characters);
2819 if (pathKeys.find(firstDir) != pathKeys.end())
2821 path = pathKeys[firstDir] + rest;
2825 wxFileName fname = path;
2829 if (fname.wxFileName::IsOk() && fname.GetFullName().empty())
2831 path = fname.GetPathWithSep() +
_(
"untitled");
2839 wxFileName fname = path;
2840 wxString dir = fname.GetPath();
2843 fname.wxFileName::IsOk() && wxFileName::DirExists(dir) &&
2844 !fname.GetFullName().empty());
2849 int seconds =
static_cast<int>(t);
2850 int hh = seconds / 3600;
2851 int mm = seconds % 3600;
2853 return wxString::Format(
"%d:%d:%.3f", hh, mm, t - (hh * 3600 + mm * 60));
2858 auto string =
UTF8CTOWX(getstring(xlgastring()));
2859#if !HAS_I18N_CONTEXTS
2870#if HAS_I18N_CONTEXTS
2871 auto string =
UTF8CTOWX(getstring(xlgastring()));
2872 auto context =
UTF8CTOWX(getstring(xlgastring()));
2875 wxGetTranslation(
string,
"", 0,
"", context).mb_str(wxConvUTF8));
2883 auto string1 =
UTF8CTOWX(getstring(xlgastring()));
2884 auto string2 =
UTF8CTOWX(getstring(xlgastring()));
2885 auto number = getfixnum(xlgafixnum());
2886#if !HAS_I18N_CONTEXTS
2893 wxGetTranslation(string1, string2, number).mb_str(wxConvUTF8));
2898#if HAS_I18N_CONTEXTS
2899 auto string1 =
UTF8CTOWX(getstring(xlgastring()));
2900 auto string2 =
UTF8CTOWX(getstring(xlgastring()));
2901 auto number = getfixnum(xlgafixnum());
2902 auto context =
UTF8CTOWX(getstring(xlgastring()));
2904 return cvstring(wxGetTranslation(string1, string2, number,
"", context)
2905 .mb_str(wxConvUTF8));
2914 unsigned char* dstp;
2915 dst = new_string((
int)(
size + 2));
2916 dstp = getstring(dst);
2931 wxString Left = Str.BeforeLast(
'\n').BeforeLast(
'\n').ToAscii();
2932 wxString Right = Str.BeforeLast(
'\n').AfterLast(
'\n').ToAscii();
2933 message = cvstring(Left);
2934 success = Right.EndsWith(
"OK") ? s_true :
nullptr;
2935 dst = cons(message, success);
2954 unsigned char* leftp;
2962 leftp = getstring(src);
2976 static bool firstTime =
true;
2982 static const FUNDEF functions[] = {
2988 xlbindfunctions(functions, WXSIZEOF(functions));
SimpleGuard< R > MakeSimpleGuard(R value) noexcept(noexcept(SimpleGuard< R >{ value }))
Convert a value to a handler function returning that value, suitable for GuardedCall<R>
Toolkit-neutral facade for basic user interface services.
#define NYQUISTEFFECTS_FAMILY
wxString FileExtension
File extension, not including any leading dot.
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
STRINGS_API const wxString & GetCustomTranslation(const wxString &str1)
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
void * ExecForLisp(char *pIn)
void * nyq_make_opaque_string(int size, unsigned char *src)
void * nyq_reformat_aud_do_response(const wxString &Str)
static const wxChar * KEY_Command
static const wxChar * KEY_Parameters
static void RegisterFunctions()
#define UNINITIALIZED_CONTROL
#define NYQUIST_WORKER_ID
#define NYQUIST_PROMPT_ID
#define NYQUIST_PROMPT_NAME
audacity::BasicSettings * gPrefs
an object holding per-project preferred sample rate
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
bool WriteEnum(const wxString &key, int value, const EnumValueSymbol choices[], size_t nChoices)
bool ReadEnum(const wxString &key, int *pi, const EnumValueSymbol choices[], size_t nChoices, const ObsoleteMap obsoletes[]=nullptr, size_t nObsoletes=0) const
bool SetParameters(const wxString &parms)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
void SetPreviewFullSelectionFlag(bool previewDurationFlag)
bool IsPreviewing() const
void SetLinearEffectFlag(bool linearEffectFlag)
const TrackList * inputTracks() const
std::shared_ptr< TrackList > mTracks
wxArrayString mPresetNames
const AudacityProject * FindProject() const
bool TrackGroupProgress(int whichGroup, double frac, const TranslatableString &={}) const
bool Delegate(Effect &delegate, EffectSettings &settings, InstanceFinder finder={})
Re-invoke DoEffect on another Effect object that implements the work.
bool TotalProgress(double frac, const TranslatableString &={}) const
bool TrackProgress(int whichTrack, double frac, const TranslatableString &={}) const
bool IsBatchProcessing() const override
int GetNumWaveGroups() const
Performs effect computation.
EffectManager is the class that handles effects and effect categories.
void SetSkipStateFlag(bool flag)
static EffectManager & Get()
Use this object to copy the input tracks to tentative outputTracks.
const Track * GetMatchingInput(const Track &outTrack) const
Gets the matching input track for the given output track if it finds its match, else nullptr.
Track * AddToOutputTracks(const std::shared_ptr< Track > &t)
Use this to add an output track, not corresponding to an input.
std::pair< double, double > TimeInterval
TrackList & Get()
Expose the output track list for iterations or even erasures.
static NyquistSettings & GetSettings(EffectSettings &settings)
Assume settings originated from MakeSettings() and copies thereof.
std::vector< FileType > FileTypes
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
static wxString ToString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, always uses the dot as decimal separator.
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
A LabelTrack is a Track that holds labels (LabelStruct).
static wxString GetDefaultName()
A Track that is used for Midi notes. (Somewhat old code).
A control on a NyquistDialog.
std::vector< EnumValueSymbol > choices
FileNames::FileTypes fileTypes
An Effect that calls up a Nyquist (XLISP) plug-in, i.e. many possible effects from this one class.
bool VisitSettings(SettingsVisitor &visitor, EffectSettings &settings) override
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
void SetCommand(const wxString &cmd)
bool Parse(Tokenizer &tokenizer, const wxString &line, bool eof, bool first)
bool Process(EffectInstance &instance, EffectSettings &settings) override
wxString EscapeString(const wxString &inStr)
static void resolveFilePath(wxString &path, FileExtension extension={})
bool validatePath(wxString path)
VendorSymbol GetVendor() const override
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
FileNames::FileType ParseFileType(const wxString &text)
bool ProcessOne(NyxContext &nyxContext, EffectOutputTracks *pOutputs)
EffectType GetType() const override
Type determines how it behaves.
TranslatableString mCopyright
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
TranslatableString mInitError
TranslatableString mPromptName
wxArrayString mCategories
static void StaticOSCallback(void *userdata)
unsigned mNumSelectedChannels
static std::vector< EnumValueSymbol > ParseChoice(const wxString &text)
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
wxString GetVersion() const override
wxFileName mFileName
Name of the Nyquist script file this effect is loaded from.
static wxString UnQuote(const wxString &s, bool allowParens=true, wxString *pExtraString=nullptr)
static void StaticOutputCallback(int c, void *userdata)
wxDateTime mFileModified
When the script was last modified on disk.
FileExtensions ParseFileExtensions(const wxString &text)
TranslatableString mAction
TranslatableString mDebugOutput
FileNames::FileTypes ParseFileTypes(const wxString &text)
PluginPath GetPath() const override
static double GetCtrlValue(const wxString &s)
bool ParseProgram(wxInputStream &stream)
EffectType GetClassification() const override
Determines which menu it appears in; default same as GetType().
FilePath HelpPage() const override
Fully qualified local help file name, default is empty.
TranslatableString mReleaseVersion
bool EnablesDebug() const override
Whether the effect dialog should have a Debug button; default, always false.
static TranslatableString UnQuoteMsgid(const wxString &s, bool allowParens=true, wxString *pExtraString=nullptr)
std::pair< bool, FilePath > CheckHelpPage() const
static wxString NyquistToWxString(const char *nyqString)
wxString ToTimeFormat(double t)
TranslatableString mAuthor
NyquistBase(const wxString &fName)
TranslatableString GetDescription() const override
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
bool ParseCommand(const wxString &cmd)
std::vector< NyqControl > mControls
int SetLispVarsFromParameters(const CommandParameters &parms, bool bTestOnly)
void OutputCallback(int c)
TranslatableString mName
Name of the Effect (untranslated)
bool DoLoadSettings(const CommandParameters &parms, EffectSettings &settings)
ComponentInterfaceSymbol GetSymbol() const override
static FilePaths GetNyquistSearchPath()
Unit slope but with either a jump (pasting more) or a flat interval (pasting less)
static ProjectRate & Get(AudacityProject &project)
Defines a selected portion of a project.
Visitor of effect or command parameters. This is a base class with lots of virtual functions that do ...
virtual void Define(Arg< bool > var, const wxChar *key, bool vdefault, bool vmin=false, bool vmax=false, bool vscl=false)
virtual void DefineEnum(Arg< int > var, const wxChar *key, int vdefault, const EnumValueSymbol strings[], size_t nStrings)
SettingsVisitor that gets parameter values into a string.
SettingsVisitor that sets parameters to a value (from a string)
bool SpectralSelectionEnabled() const
static SpectrogramSettings & Get(const WaveTrack &track)
static TrackIterRange< Track > Group(Track &track)
static bool IsSyncLockSelected(const Track &track)
A kind of Track used to 'warp time'.
Abstract base class for an object holding data associated with points on a time axis.
R TypeSwitch(const Functions &...functions)
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
auto Selected() -> TrackIterRange< TrackType >
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
A Track that contains audio waveform data.
IntervalHolders SortedIntervalArray()
Return all WaveClips sorted by clip play start time.
size_t NChannels() const override
A constant property.
std::shared_ptr< WaveTrack > Holder
virtual bool Read(const wxString &key, bool *value) const =0
Positions or offsets within audio files need a wide type.
long long as_long_long() const
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
FILES_API FilePath PlugInDir()
The user plug-in directory (not a system one)
FILES_API FilePath HtmlHelpDir()
FILES_API wxFileNameWrapper DefaultToDocumentsFolder(const wxString &preference)
FILES_API void AddUniquePathToPathList(const FilePath &path, FilePaths &pathList)
FILES_API FilePath BaseDir()
FILES_API FilePath DataDir()
Audacity user data directory.
FILES_API FilePath FindDefaultPath(Operation op)
FILES_API const FilePaths & AudacityPathList()
A list of directories that should be searched for Audacity files (plug-ins, help files,...
wxString GetSystemLanguageCode(const FilePaths &pathList)
FILES_API wxString TempDir()
WAVE_TRACK_API std::pair< float, float > GetMinMax(const WaveChannel &channel, double t0, double t1, bool mayThrow=true)
WAVE_TRACK_API float GetRMS(const WaveChannel &channel, double t0, double t1, bool mayThrow=true)
ProjectFileIOExtensionRegistry::Extension extension
wxString GetClipBoundaries(const Track *t)
const char * end(const char *str) noexcept
const char * begin(const char *str) noexcept
__finl float_x4 __vecc sqrt(const float_x4 &a)
MessageBoxOptions && IconStyle(Icon style) &&
Externalized state of a plug-in.
Buffer mCurBuffer[2]
used only in GetCallback
WaveTrack::Holder mOutputTrack
int PutCallback(float *buffer, int channel, int64_t start, int64_t len, int64_t totlen)
NyxContext(ProgressReport progressReport, double scale, double progressTot)
sampleCount mCurBufferStart[2]
std::unique_ptr< float[]> Buffer
const double mProgressTot
WaveChannel * mCurTrack[2]
static int StaticPutCallback(float *buffer, int channel, int64_t start, int64_t len, int64_t totlen, void *userdata)
unsigned mCurNumChannels
Not used in the callbacks.
const ProgressReport mProgressReport
std::function< bool(double)> ProgressReport
std::exception_ptr mpException
WaveTrack * mCurChannelGroup
int GetCallback(float *buffer, int channel, int64_t start, int64_t len, int64_t totlen)
static int StaticGetCallback(float *buffer, int channel, int64_t start, int64_t len, int64_t totlen, void *userdata)
bool Tokenize(const wxString &line, bool eof, size_t trimStart, size_t trimEnd)