Audacity 3.2.0
ImportMIDI.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ImportMIDI.cpp
6
7 Dominic Mazzoni
8
9**********************************************************************/
10
11#include <wx/defs.h>
12#include <wx/ffile.h>
13#include <wx/frame.h>
14
15#if defined(USE_MIDI)
16
17
18#include "WrapAllegro.h"
19
20#include "Import.h"
21#include "ImportPlugin.h"
23#include "NoteTrack.h"
25#include "Project.h"
26#include "ProjectFileIO.h"
27#include "ProjectHistory.h"
28#include "Viewport.h"
29#include "ProjectWindows.h"
30#include "SelectFile.h"
31#include "SelectUtilities.h"
32#include "AudacityMessageBox.h"
33#include "widgets/FileHistory.h"
34#include "ProgressDialog.h"
35
36namespace {
37
38bool ImportMIDI(const FilePath &fName, NoteTrack * dest);
39
40// Given an existing project, try to import into it, return true on success
42{
43 auto &projectFileIO = ProjectFileIO::Get( project );
44 auto &tracks = TrackList::Get( project );
45 auto newTrack = std::make_shared<NoteTrack>();
46 bool initiallyEmpty = tracks.empty();
47
48 if (::ImportMIDI(fileName, newTrack.get())) {
49
51 auto pTrack = tracks.Add( newTrack );
52 pTrack->SetSelected(true);
53
54 // Fix the bug 2109.
55 // In case the project had soloed tracks before importing,
56 // the newly imported track is muted.
57 const bool projectHasSolo =
58 !(tracks.Any<PlayableTrack>() + &PlayableTrack::GetSolo).empty();
59#ifdef EXPERIMENTAL_MIDI_OUT
60 if (projectHasSolo)
61 pTrack->SetMute(true);
62#endif
63
65 .PushState(
66 XO("Imported MIDI from '%s'").Format( fileName ),
67 XO("Import MIDI")
68 );
69
71 FileHistory::Global().Append(fileName);
72
73 // If the project was clean and temporary (not permanently saved), then set
74 // the filename to the just imported path.
75 if (initiallyEmpty && projectFileIO.IsTemporary()) {
76 wxFileName fn(fileName);
77 project.SetProjectName(fn.GetName());
78 project.SetInitialImportPath(fn.GetPath());
79 projectFileIO.SetProjectTitle();
80 }
81 return true;
82 }
83 else
84 return false;
85}
86
87bool ImportMIDI(const FilePath &fName, NoteTrack * dest)
88{
89 if (fName.length() <= 4){
91 XO("Could not open file %s: Filename too short.").Format( fName ) );
92 return false;
93 }
94
95 bool is_midi = false;
96 if (fName.Right(4).CmpNoCase(wxT(".mid")) == 0 || fName.Right(5).CmpNoCase(wxT(".midi")) == 0)
97 is_midi = true;
98 else if(fName.Right(4).CmpNoCase(wxT(".gro")) != 0) {
100 XO("Could not open file %s: Incorrect filetype.").Format( fName ) );
101 return false;
102 }
103
104 wxFFile mf(fName, wxT("rb"));
105 if (!mf.IsOpened()) {
107 XO("Could not open file %s.").Format( fName ) );
108 return false;
109 }
110
111 double offset = 0.0;
112 auto new_seq = std::make_unique<Alg_seq>(fName.mb_str(), is_midi, &offset);
113
114 //Should we also check if(seq->tracks() == 0) ?
115 if(new_seq->get_read_error() == alg_error_open){
117 XO("Could not open file %s.").Format( fName ) );
118 mf.Close();
119 return false;
120 }
121
122 dest->SetSequence(std::move(new_seq));
123 dest->MoveTo(offset);
124 wxString trackNameBase = fName.AfterLast(wxFILE_SEP_PATH).BeforeLast('.');
125 dest->SetName(trackNameBase);
126 mf.Close();
127
128 NoteTrackRange::Get(*dest).ZoomAllNotes(&dest->GetSeq());
129 return true;
130}
131
132}
133
134// Insert a menu item
135#include "CommandContext.h"
136#include "MenuRegistry.h"
137#include "CommonCommandFlags.h"
138
139namespace {
140using namespace MenuRegistry;
141
142void OnImportMIDI(const CommandContext &context)
143{
144 auto &project = context.project;
145 auto &window = GetProjectFrame( project );
146
147 wxString fileName = SelectFile(FileNames::Operation::Open,
148 XO("Select a MIDI file"),
149 wxEmptyString, // Path
150 wxT(""), // Name
151 wxT(""), // Extension
152 {
153 { XO("MIDI and Allegro files"),
154 { wxT("mid"), wxT("midi"), wxT("gro"), }, true },
155 { XO("MIDI files"),
156 { wxT("mid"), wxT("midi"), }, true },
157 { XO("Allegro files"),
158 { wxT("gro"), }, true },
160 },
161 wxRESIZE_BORDER, // Flags
162 &window); // Parent
163
164 if (!fileName.empty())
165 DoImportMIDI(project, fileName);
166}
167
169 Command( wxT("ImportMIDI"), XXO("&MIDI..."), OnImportMIDI,
171 { wxT("File/Import-Export/Import"),
172 { OrderingHint::After, {"ImportAudio"} } }
173};
174
175constexpr auto exts = {
176 wxT("gro"),
177 wxT("midi"),
178 wxT("mid"),
179};
180
181const auto DESC = XO("MIDI files");
182
184{
185public:
186 explicit MIDIImportFileHandle(const FilePath &fileName)
187 : mFileName{ fileName }
188 {}
189
191
192 FilePath GetFilename() const override { return mFileName; }
193
195
197 {
198 // TODO: Get Uncompressed byte count.
199 return 0;
200 }
201
202 wxInt32 GetStreamCount() override { return 1; }
203
205 {
206 static TranslatableStrings empty;
207 return empty;
208 }
209
210 void Import(
211 ImportProgressListener& progressListener, WaveTrackFactory* trackFactory,
212 TrackHolders& outTracks, Tags* tags,
213 std::optional<LibFileFormats::AcidizerTags>& outAcidTags) override;
214
215 void Cancel() override {}
216 void Stop() override {}
217
218 void SetStreamUsage(wxInt32, bool) override {}
219
221};
222
223void MIDIImportFileHandle::Import(
224 ImportProgressListener& progressListener, WaveTrackFactory*,
225 TrackHolders& outTracks, Tags*, std::optional<LibFileFormats::AcidizerTags>&)
226{
227 auto newTrack = std::make_shared<NoteTrack>();
228 if (::ImportMIDI(mFileName, newTrack.get())) {
229 outTracks.push_back(TrackList::Temporary(nullptr, newTrack));
230 progressListener.OnImportResult(
232 }
233 else
234 progressListener.OnImportResult(
236}
237
238class MIDIImportPlugin final : public ImportPlugin
239{
240public:
243 {}
244 ~MIDIImportPlugin() override {}
245
246 wxString GetPluginStringID() override { return wxT("portsmf"); }
247
249
250 std::unique_ptr<ImportFileHandle> Open(const FilePath &fileName,
251 AudacityProject *project) override
252 {
253 return std::make_unique<MIDIImportFileHandle>(fileName);
254 }
255};
256
258 std::make_unique<MIDIImportPlugin>()
259};
260
261}
262
263#include "ModuleConstants.h"
265
266#endif
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const ReservedCommandFlag & AudioIONotBusyFlag()
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
The interface that all file import "plugins" (if you want to call them that) must implement....
std::vector< std::shared_ptr< TrackList > > TrackHolders
Definition: ImportRaw.h:24
#define DEFINE_MODULE_ENTRIES
wxString FilePath
Definition: Project.h:21
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
accessors for certain important windows associated with each project
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
const auto tracks
const auto project
std::vector< TranslatableString > TranslatableStrings
static const auto fn
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
void Append(const FilePath &file)
Definition: FileHistory.h:46
static FileHistory & Global()
Definition: FileHistory.cpp:39
FILES_API const FileType AllFiles
Definition: FileNames.h:70
Abstract base class used in importing a file.
Base class for FlacImportFileHandle, LOFImportFileHandle, MP3ImportFileHandle, OggImportFileHandle an...
Definition: ImportPlugin.h:111
unsigned long long ByteCount
Definition: ImportPlugin.h:114
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:67
Interface used to report on import state and progress.
virtual void OnImportResult(ImportResult result)=0
Used to report on import result for file handle passed as argument to OnImportFileOpened.
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:86
void SetSequence(std::unique_ptr< Alg_seq > &&seq)
Definition: NoteTrack.cpp:263
void MoveTo(double origin) override
Change start time to given time point.
Definition: NoteTrack.h:106
Alg_seq & GetSeq() const
Definition: NoteTrack.cpp:146
static NoteTrackRange & Get(const NoteTrack &track)
Allow mutative access to attached data of a const track.
void ZoomAllNotes(Alg_seq *pSeq)
Zooms so that all notes are visible.
AudioTrack subclass that can also be audibly replayed by the program.
Definition: PlayableTrack.h:40
bool GetSolo() const
Definition: PlayableTrack.h:48
static ProjectFileIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
Definition: Registry.h:388
ID3 Tags (for MP3)
Definition: Tags.h:73
void SetName(const wxString &n)
Definition: Track.cpp:61
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
static TrackListHolder Temporary(AudacityProject *pProject, const Track::Holder &left={}, const Track::Holder &right={})
Definition: Track.cpp:1418
Holds a msgid for the translation catalog; may also bind format arguments.
void ZoomFitHorizontallyAndShowTrack(Track *pTrack)
Definition: Viewport.cpp:437
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:32
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:1279
TranslatableString GetPluginFormatDescription() override
Definition: ImportMIDI.cpp:248
std::unique_ptr< ImportFileHandle > Open(const FilePath &fileName, AudacityProject *project) override
Definition: ImportMIDI.cpp:250
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
constexpr auto Command
Definition: MenuRegistry.h:456
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
void SelectNone(AudacityProject &project)
bool DoImportMIDI(AudacityProject &project, const FilePath &fileName)
Definition: ImportMIDI.cpp:41
Importer::RegisteredImportPlugin registered
Definition: ImportMIDI.cpp:257
void OnImportMIDI(const CommandContext &context)
Definition: ImportMIDI.cpp:142
bool ImportMIDI(const FilePath &fName, NoteTrack *dest)
Definition: ImportMIDI.cpp:87
const TranslatableStrings & GetStreamInfo() override
Definition: ImportMIDI.cpp:204