1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   Nyquist.h
6 
7   Dominic Mazzoni
8 
9 **********************************************************************/
10 
11 #ifndef __AUDACITY_EFFECT_NYQUIST__
12 #define __AUDACITY_EFFECT_NYQUIST__
13 
14 #include "../Effect.h"
15 #include "FileNames.h"
16 
17 #include "nyx.h"
18 
19 class wxArrayString;
20 class wxFileName;
21 class wxCheckBox;
22 class wxTextCtrl;
23 
24 #define NYQUISTEFFECTS_VERSION wxT("1.0.0.0")
25 
26 enum NyqControlType
27 {
28    NYQ_CTRL_INT,
29    NYQ_CTRL_FLOAT,
30    NYQ_CTRL_STRING,
31    NYQ_CTRL_CHOICE,
32    NYQ_CTRL_INT_TEXT,
33    NYQ_CTRL_FLOAT_TEXT,
34    NYQ_CTRL_TEXT,
35    NYQ_CTRL_TIME,
36    NYQ_CTRL_FILE,
37 };
38 
39 class NyqControl
40 {
41 public:
42    NyqControl() = default;
43    NyqControl( const NyqControl& ) = default;
44    NyqControl &operator = ( const NyqControl & ) = default;
45    //NyqControl( NyqControl && ) = default;
46    //NyqControl &operator = ( NyqControl && ) = default;
47 
48    int type;
49    wxString var;
50    wxString name;
51    wxString label;
52    std::vector<EnumValueSymbol> choices;
53    FileNames::FileTypes fileTypes;
54    wxString valStr;
55    wxString lowStr;
56    wxString highStr;
57    double val;
58    double low;
59    double high;
60    int ticks;
61 };
62 
63 
64 class AUDACITY_DLL_API NyquistEffect final : public Effect
65 {
66 public:
67 
68    /** @param fName File name of the Nyquist script defining this effect. If
69     * an empty string, then prompt the user for the Nyquist code to interpret.
70     */
71    NyquistEffect(const wxString &fName);
72    virtual ~NyquistEffect();
73 
74    // ComponentInterface implementation
75 
76    PluginPath GetPath() override;
77    ComponentInterfaceSymbol GetSymbol() override;
78    VendorSymbol GetVendor() override;
79    wxString GetVersion() override;
80    TranslatableString GetDescription() override;
81 
82    ManualPageID ManualPage() override;
83    FilePath HelpPage() override;
84 
85    // EffectDefinitionInterface implementation
86 
87    EffectType GetType() override;
88    EffectType GetClassification() override;
89    EffectFamilySymbol GetFamily() override;
90    bool IsInteractive() override;
91    bool IsDefault() override;
92 
93    // EffectClientInterface implementation
94 
95    bool DefineParams( ShuttleParams & S ) override;
96    bool GetAutomationParameters(CommandParameters & parms) override;
97    bool SetAutomationParameters(CommandParameters & parms) override;
98    int SetLispVarsFromParameters(CommandParameters & parms, bool bTestOnly);
99 
100    // Effect implementation
101 
102    bool Init() override;
103    bool CheckWhetherSkipEffect() override;
104    bool Process() override;
105    bool ShowInterface( wxWindow &parent,
106       const EffectDialogFactory &factory, bool forceModal = false) override;
107    void PopulateOrExchange(ShuttleGui & S) override;
108    bool TransferDataToWindow() override;
109    bool TransferDataFromWindow() override;
110 
111    // NyquistEffect implementation
112    // For Nyquist Workbench support
113    void RedirectOutput();
114    void SetCommand(const wxString &cmd);
115    void Continue();
116    void Break();
117    void Stop();
118 
119 private:
120    static int mReentryCount;
121    // NyquistEffect implementation
122 
123    bool ProcessOne();
124 
125    void BuildPromptWindow(ShuttleGui & S);
126    void BuildEffectWindow(ShuttleGui & S);
127 
128    bool TransferDataToPromptWindow();
129    bool TransferDataToEffectWindow();
130 
131    bool TransferDataFromPromptWindow();
132    bool TransferDataFromEffectWindow();
133 
134    bool IsOk();
InitializationError()135    const TranslatableString &InitializationError() const { return mInitError; }
136 
137    static FilePaths GetNyquistSearchPath();
138 
139    static wxString NyquistToWxString(const char *nyqString);
140    wxString EscapeString(const wxString & inStr);
141    static std::vector<EnumValueSymbol> ParseChoice(const wxString & text);
142 
143    FileExtensions ParseFileExtensions(const wxString & text);
144    FileNames::FileType ParseFileType(const wxString & text);
145    FileNames::FileTypes ParseFileTypes(const wxString & text);
146 
147    static int StaticGetCallback(float *buffer, int channel,
148                                 int64_t start, int64_t len, int64_t totlen,
149                                 void *userdata);
150    static int StaticPutCallback(float *buffer, int channel,
151                                 int64_t start, int64_t len, int64_t totlen,
152                                 void *userdata);
153    static void StaticOutputCallback(int c, void *userdata);
154    static void StaticOSCallback(void *userdata);
155 
156    int GetCallback(float *buffer, int channel,
157                    int64_t start, int64_t len, int64_t totlen);
158    int PutCallback(float *buffer, int channel,
159                    int64_t start, int64_t len, int64_t totlen);
160    void OutputCallback(int c);
161    void OSCallback();
162 
163    void ParseFile();
164    bool ParseCommand(const wxString & cmd);
165    bool ParseProgram(wxInputStream & stream);
166    struct Tokenizer {
167       bool sl { false };
168       bool q { false };
169       int paren{ 0 };
170       wxString tok;
171       wxArrayStringEx tokens;
172 
173       bool Tokenize(
174          const wxString &line, bool eof,
175          size_t trimStart, size_t trimEnd);
176    };
177    bool Parse(Tokenizer &tokenizer, const wxString &line, bool eof, bool first);
178 
179    static TranslatableString UnQuoteMsgid(const wxString &s, bool allowParens = true,
180                            wxString *pExtraString = nullptr);
181    static wxString UnQuote(const wxString &s, bool allowParens = true,
182                            wxString *pExtraString = nullptr);
183    double GetCtrlValue(const wxString &s);
184 
185    void OnLoad(wxCommandEvent & evt);
186    void OnSave(wxCommandEvent & evt);
187    void OnDebug(wxCommandEvent & evt);
188 
189    void OnText(wxCommandEvent & evt);
190    void OnSlider(wxCommandEvent & evt);
191    void OnChoice(wxCommandEvent & evt);
192    void OnTime(wxCommandEvent & evt);
193    void OnFileButton(wxCommandEvent & evt);
194 
195    void resolveFilePath(wxString & path, FileExtension extension = {});
196    bool validatePath(wxString path);
197    wxString ToTimeFormat(double t);
198 
199 private:
200 
201    wxString          mXlispPath;
202 
203    wxFileName        mFileName;  ///< Name of the Nyquist script file this effect is loaded from
204    wxDateTime        mFileModified; ///< When the script was last modified on disk
205 
206    bool              mStop;
207    bool              mBreak;
208    bool              mCont;
209 
210    bool              mFoundType;
211    bool              mCompiler;
212    bool              mTrace;   // True when *tracenable* or *sal-traceback* are enabled
213    bool              mIsSal;
214    bool              mExternal;
215    bool              mIsSpectral;
216    bool              mIsTool;
217    /** True if the code to execute is obtained interactively from the user via
218     * the "Nyquist Effect Prompt", or "Nyquist Prompt", false for all other effects (lisp code read from
219     * files)
220     */
221    bool              mIsPrompt;
222    bool              mOK;
223    TranslatableString mInitError;
224    wxString          mInputCmd; // history: exactly what the user typed
225    wxString          mParameters; // The parameters of to be fed to a nested prompt
226    wxString          mCmd;      // the command to be processed
227    TranslatableString mName;   ///< Name of the Effect (untranslated)
228    TranslatableString mPromptName; // If a prompt, we need to remember original name.
229    TranslatableString mAction;
230    TranslatableString mInfo;
231    TranslatableString mAuthor;
232    // Version number of the specific plug-in (not to be confused with mVersion)
233    // For shipped plug-ins this will be the same as the Audacity release version
234    // when the plug-in was last modified.
235    TranslatableString mReleaseVersion;
236    TranslatableString mCopyright;
237    wxString          mManPage;   // ONLY use if a help page exists in the manual.
238    wxString          mHelpFile;
239    bool              mHelpFileExists;
240    EffectType        mType;
241    EffectType        mPromptType; // If a prompt, need to remember original type.
242 
243    bool              mEnablePreview;
244    bool              mDebugButton;  // Set to false to disable Debug button.
245 
246    bool              mDebug;        // When true, debug window is shown.
247    bool              mRedirectOutput;
248    bool              mProjectChanged;
249    wxString          mDebugOutputStr;
250    TranslatableString mDebugOutput;
251 
252    int               mVersion;   // Syntactic version of Nyquist plug-in (not to be confused with mReleaseVersion)
253    std::vector<NyqControl>   mControls;
254 
255    unsigned          mCurNumChannels;
256    WaveTrack         *mCurTrack[2];
257    sampleCount       mCurStart[2];
258    sampleCount       mCurLen;
259    sampleCount       mMaxLen;
260    int               mTrackIndex;
261    bool              mFirstInGroup;
262    double            mOutputTime;
263    unsigned          mCount;
264    unsigned          mNumSelectedChannels;
265    double            mProgressIn;
266    double            mProgressOut;
267    double            mProgressTot;
268    double            mScale;
269 
270    using Buffer = std::unique_ptr<float[]>;
271    Buffer            mCurBuffer[2];
272    sampleCount       mCurBufferStart[2];
273    size_t            mCurBufferLen[2];
274 
275    WaveTrack        *mOutputTrack[2];
276 
277    wxArrayString     mCategories;
278 
279    wxString          mProps;
280    wxString          mPerTrackProps;
281 
282    bool              mRestoreSplits;
283    int               mMergeClips;
284 
285    wxTextCtrl *mCommandText;
286 
287    std::exception_ptr mpException {};
288 
289    DECLARE_EVENT_TABLE()
290 
291    friend class NyquistEffectsModule;
292 };
293 
294 class NyquistOutputDialog final : public wxDialogWrapper
295 {
296 public:
297    NyquistOutputDialog(wxWindow * parent, wxWindowID id,
298                        const TranslatableString & title,
299                        const TranslatableString & prompt,
300                        const TranslatableString &message);
301 
302 private:
303    void OnOk(wxCommandEvent & event);
304 
305 private:
306    DECLARE_EVENT_TABLE()
307 };
308 
309 
310 #endif
311