1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   Export.h
6 
7   Dominic Mazzoni
8 
9 **********************************************************************/
10 
11 #ifndef __AUDACITY_EXPORT__
12 #define __AUDACITY_EXPORT__
13 
14 #include <functional>
15 #include <vector>
16 #include <wx/filename.h> // member variable
17 #include "Identifier.h"
18 #include "SampleFormat.h"
19 #include "../widgets/wxPanelWrapper.h" // to inherit
20 #include "FileNames.h" // for FileTypes
21 
22 #include "Registry.h"
23 
24 class wxArrayString;
25 class FileDialogWrapper;
26 class wxFileCtrlEvent;
27 class wxMemoryDC;
28 class wxSimplebook;
29 class wxStaticText;
30 class AudacityProject;
31 class WaveTrack;
32 class Tags;
33 class TrackList;
34 class MixerSpec;
35 class ProgressDialog;
36 class ShuttleGui;
37 class Mixer;
38 using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >;
39 namespace BasicUI{ enum class ProgressResult : unsigned; }
40 class wxFileNameWrapper;
41 
42 class AUDACITY_DLL_API FormatInfo
43 {
44    public:
FormatInfo()45       FormatInfo() {}
46       FormatInfo( const FormatInfo & ) = default;
47       FormatInfo &operator = ( const FormatInfo & ) = default;
48       //FormatInfo( FormatInfo && ) = default;
49       //FormatInfo &operator = ( FormatInfo && ) = default;
~FormatInfo()50       ~FormatInfo() {}
51 
52       wxString mFormat;
53       TranslatableString mDescription;
54       // wxString mExtension;
55       FileExtensions mExtensions;
56       FileNames::FileTypes mMask;
57       unsigned mMaxChannels;
58       bool mCanMetaData;
59 };
60 
61 //----------------------------------------------------------------------------
62 // ExportPlugin
63 //----------------------------------------------------------------------------
64 class AUDACITY_DLL_API ExportPlugin /* not final */
65 {
66 public:
67    using ProgressResult = BasicUI::ProgressResult;
68 
69    ExportPlugin();
70    virtual ~ExportPlugin();
71 
72    int AddFormat();
73    void SetFormat(const wxString & format, int index);
74    void SetDescription(const TranslatableString & description, int index);
75    void AddExtension(const FileExtension &extension, int index);
76    void SetExtensions(FileExtensions extensions, int index);
77    void SetMask(FileNames::FileTypes mask, int index);
78    void SetMaxChannels(unsigned maxchannels, unsigned index);
79    void SetCanMetaData(bool canmetadata, int index);
80 
81    virtual int GetFormatCount();
82    virtual wxString GetFormat(int index);
83    TranslatableString GetDescription(int index);
84    /** @brief Return the (first) file name extension for the sub-format.
85     * @param index The sub-format for which the extension is wanted */
86    virtual FileExtension GetExtension(int index = 0);
87    /** @brief Return all the file name extensions used for the sub-format.
88     * @param index the sub-format for which the extension is required */
89    virtual FileExtensions GetExtensions(int index = 0);
90    FileNames::FileTypes GetMask(int index);
91    virtual unsigned GetMaxChannels(int index);
92    virtual bool GetCanMetaData(int index);
93 
94    virtual bool IsExtension(const FileExtension & ext, int index);
95 
96    virtual bool DisplayOptions(wxWindow *parent, int format = 0);
97 
98    virtual void OptionsCreate(ShuttleGui &S, int format) = 0;
99 
100    virtual bool CheckFileName(wxFileName &filename, int format = 0);
101    /** @brief Exporter plug-ins may override this to specify the number
102     * of channels in exported file. -1 for unspecified */
SetNumExportChannels()103    virtual int SetNumExportChannels() { return -1; }
104 
105    /** \brief called to export audio into a file.
106     *
107     * @param pDialog To be initialized with pointer to a NEW ProgressDialog if
108     * it was null, otherwise gives an existing dialog to be reused
109    *  (working around a problem in wxWidgets for Mac; see bug 1600)
110     * @param selectedOnly Set to true if all tracks should be mixed, to false
111     * if only the selected tracks should be mixed and exported.
112     * @param metadata A Tags object that will over-ride the one in *project and
113     * be used to tag the file that is exported.
114     * @param subformat Control which of the multiple formats this exporter is
115     * capable of exporting should be used. Used where a single export plug-in
116     * handles a number of related formats, but they have separate
117     * entries in the Format drop-down list box. For example, the options to
118     * export to "Other PCM", "AIFF 16 Bit" and "WAV 16 Bit" are all the same
119     * libsndfile export plug-in, but with subformat set to 0, 1, and 2
120     * respectively.
121     * @return ProgressResult::Failed or ProgressResult::Cancelled if export
122     * fails to complete for any reason, in which case this function is
123     * responsible for alerting the user.  Otherwise ProgressResult::Success or
124     * ProgressResult::Stopped
125     */
126    virtual ProgressResult Export(AudacityProject *project,
127                        std::unique_ptr<ProgressDialog> &pDialog,
128                        unsigned channels,
129                        const wxFileNameWrapper &fName,
130                        bool selectedOnly,
131                        double t0,
132                        double t1,
133                        MixerSpec *mixerSpec = NULL,
134                        const Tags *metadata = NULL,
135                        int subformat = 0) = 0;
136 
137 protected:
138    std::unique_ptr<Mixer> CreateMixer(const TrackList &tracks,
139          bool selectionOnly,
140          double startTime, double stopTime,
141          unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
142          double outRate, sampleFormat outFormat,
143          MixerSpec *mixerSpec);
144 
145    // Create or recycle a dialog.
146    static void InitProgress(std::unique_ptr<ProgressDialog> &pDialog,
147          const TranslatableString &title, const TranslatableString &message);
148    static void InitProgress(std::unique_ptr<ProgressDialog> &pDialog,
149          const wxFileNameWrapper &title, const TranslatableString &message);
150 
151 private:
152    std::vector<FormatInfo> mFormatInfos;
153 };
154 
155 using ExportPluginArray = std::vector < std::unique_ptr< ExportPlugin > > ;
156 
157 //----------------------------------------------------------------------------
158 // Exporter
159 //----------------------------------------------------------------------------
160 
161 // For a file suffix change from the options.
162 wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
163    AUDACITY_FILE_SUFFIX_EVENT, wxCommandEvent);
164 
165 class  AUDACITY_DLL_API Exporter final : public wxEvtHandler
166 {
167 public:
168 
169    using ExportPluginFactory =
170       std::function< std::unique_ptr< ExportPlugin >() >;
171 
172    // Objects of this type are statically constructed in files implementing
173    // subclasses of ExportPlugin
174    // Register factories, not plugin objects themselves, which allows them
175    // to have some fresh state variables each time export begins again
176    // and to compute translated strings for the current locale
177    struct AUDACITY_DLL_API RegisteredExportPlugin{
178       RegisteredExportPlugin(
179          const Identifier &id, // an internal string naming the plug-in
180          const ExportPluginFactory&,
181          const Registry::Placement &placement = { wxEmptyString, {} } );
182    };
183 
184    static bool DoEditMetadata(AudacityProject &project,
185       const TranslatableString &title,
186       const TranslatableString &shortUndoDescription, bool force);
187 
188    Exporter( AudacityProject &project );
189    virtual ~Exporter();
190 
191    void SetFileDialogTitle( const TranslatableString & DialogTitle );
SetDefaultFormat(const FileExtension & Format)192    void SetDefaultFormat( const FileExtension & Format ){ mFormatName = Format;};
193 
194    bool Process(bool selectedOnly,
195                 double t0, double t1);
196    bool Process(unsigned numChannels,
197                 const FileExtension &type, const wxString & filename,
198                 bool selectedOnly, double t0, double t1);
199 
200    void DisplayOptions(int index);
201    int FindFormatIndex(int exportindex);
202 
203    const ExportPluginArray &GetPlugins();
204 
205    // Auto Export from Timer Recording
206    bool ProcessFromTimerRecording(bool selectedOnly,
207                                   double t0,
208                                   double t1,
209                                   wxFileName fnFile,
210                                   int iFormat,
211                                   int iSubFormat,
212                                   int iFilterIndex);
213    bool SetAutoExportOptions();
214    int GetAutoExportFormat();
215    int GetAutoExportSubFormat();
216    int GetAutoExportFilterIndex();
217    wxFileName GetAutoExportFileName();
218    void OnExtensionChanged(wxCommandEvent &evt);
219    void OnHelp(wxCommandEvent &evt);
220 
221 private:
222    bool ExamineTracks();
223    bool GetFilename();
224    bool CheckFilename();
225    bool CheckMix(bool prompt = true);
226    bool ExportTracks();
227 
228    static void CreateUserPaneCallback(wxWindow *parent, wxUIntPtr userdata);
229    void CreateUserPane(wxWindow *parent);
230    void OnFilterChanged(wxFileCtrlEvent & evt);
231 
232 private:
233    FileExtension mFormatName;
234    FileDialogWrapper *mDialog;
235    TranslatableString mFileDialogTitle;
236    AudacityProject *mProject;
237    std::unique_ptr<MixerSpec> mMixerSpec;
238 
239    ExportPluginArray mPlugins;
240 
241    wxFileName mFilename;
242    wxFileName mActualName;
243 
244    double mT0;
245    double mT1;
246    int mFilterIndex;
247    int mFormat;
248    int mSubFormat;
249    int mNumSelected;
250    unsigned mNumLeft;
251    unsigned mNumRight;
252    unsigned mNumMono;
253    unsigned mChannels;
254    bool mSelectedOnly;
255 
256    wxSimplebook *mBook;
257 
258    DECLARE_EVENT_TABLE()
259 };
260 
261 //----------------------------------------------------------------------------
262 // ExportMixerPanel
263 //----------------------------------------------------------------------------
264 class ExportMixerPanel final : public wxPanelWrapper
265 {
266 public:
267    ExportMixerPanel( wxWindow *parent, wxWindowID id,
268          MixerSpec *mixerSpec, wxArrayString trackNames,
269          const wxPoint& pos = wxDefaultPosition,
270          const wxSize& size = wxDefaultSize);
271    virtual ~ExportMixerPanel();
272 
273    void OnMouseEvent(wxMouseEvent & event);
274    void OnPaint(wxPaintEvent & event);
275 
276 private:
277    std::unique_ptr<wxBitmap> mBitmap;
278    wxRect mEnvRect;
279    int mWidth;
280    int mHeight;
281    MixerSpec *mMixerSpec;
282    ArrayOf<wxRect> mChannelRects;
283    ArrayOf<wxRect> mTrackRects;
284    int mSelectedTrack, mSelectedChannel;
285    wxArrayString mTrackNames;
286    int mBoxWidth, mChannelHeight, mTrackHeight;
287 
288    void SetFont( wxMemoryDC &memDC, const wxString &text, int width, int height );
289    double Distance( wxPoint &a, wxPoint &b );
290    bool IsOnLine( wxPoint p, wxPoint la, wxPoint lb );
291 
292    DECLARE_EVENT_TABLE()
293 };
294 
295 //----------------------------------------------------------------------------
296 // ExportMixerDialog
297 //----------------------------------------------------------------------------
298 class ExportMixerDialog final : public wxDialogWrapper
299 {
300 public:
301    // constructors and destructors
302    ExportMixerDialog( const TrackList * tracks, bool selectedOnly, unsigned maxNumChannels,
303          wxWindow *parent, wxWindowID id, const TranslatableString &title,
304          const wxPoint& pos = wxDefaultPosition,
305          const wxSize& size = wxDefaultSize,
306          long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER );
307    virtual ~ExportMixerDialog();
308 
GetMixerSpec()309    MixerSpec* GetMixerSpec() { return mMixerSpec.get(); }
310 
311 private:
312    wxStaticText *mChannelsText;
313    std::unique_ptr<MixerSpec> mMixerSpec;
314    wxArrayString mTrackNames;
315 
316 private:
317    void OnOk( wxCommandEvent &event );
318    void OnCancel( wxCommandEvent &event );
319    void OnMixerPanelHelp( wxCommandEvent &event );
320    void OnSlider( wxCommandEvent &event );
321    void OnSize( wxSizeEvent &event );
322 
323 private:
324    DECLARE_EVENT_TABLE()
325 };
326 
327 AUDACITY_DLL_API TranslatableString AudacityExportCaptionStr();
328 AUDACITY_DLL_API TranslatableString AudacityExportMessageStr();
329 
330 /// We have many Export errors that are essentially anonymous
331 /// and are distinguished only by an error code number.
332 /// Rather than repeat the code, we have it just once.
333 AUDACITY_DLL_API void ShowExportErrorDialog(wxString ErrorCode,
334    TranslatableString message = AudacityExportMessageStr(),
335    const TranslatableString& caption = AudacityExportCaptionStr(),
336    bool allowReporting = true);
337 
338 AUDACITY_DLL_API
339 void ShowDiskFullExportErrorDialog(const wxFileNameWrapper &fileName);
340 
341 #endif
342