Audacity 3.2.0
MidiIOPrefs.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 MidiIOPrefs.cpp
6
7 Joshua Haberman
8 Dominic Mazzoni
9 James Crook
10
11*******************************************************************//********************************************************************/
25
26
27#include "MidiIOPrefs.h"
28
29#ifdef EXPERIMENTAL_MIDI_OUT
30
31#include <wx/defs.h>
32
33#include <wx/choice.h>
34#include <wx/textctrl.h>
35
36#include <portmidi.h>
37
38#include "NoteTrack.h"
39#include "Prefs.h"
40#include "ShuttleGui.h"
41#include "AudacityMessageBox.h"
42
43enum {
44 HostID = 10000,
45 PlayID,
48};
49
50BEGIN_EVENT_TABLE(MidiIOPrefs, PrefsPanel)
51 EVT_CHOICE(HostID, MidiIOPrefs::OnHost)
52// EVT_CHOICE(RecordID, MidiIOPrefs::OnDevice)
54
55MidiIOPrefs::MidiIOPrefs(wxWindow * parent, wxWindowID winid)
56/* i18n-hint: untranslatable acronym for "Musical Instrument Device Interface" */
57: PrefsPanel(parent, winid, XO("MIDI Devices"))
58{
59 Populate();
60}
61
62MidiIOPrefs::~MidiIOPrefs()
63{
64}
65
66ComponentInterfaceSymbol MidiIOPrefs::GetSymbol() const
67{
68 return MIDI_IO_PREFS_PLUGIN_SYMBOL;
69}
70
71TranslatableString MidiIOPrefs::GetDescription() const
72{
73 return XO("Preferences for MidiIO");
74}
75
76ManualPageID MidiIOPrefs::HelpPageName()
77{
78 return "MIDI_Devices_Preferences";
79}
80
81void MidiIOPrefs::Populate()
82{
83 // First any pre-processing for constructing the GUI.
84 GetNamesAndLabels();
85
86 // Get current setting for devices
87 mPlayDevice = MIDIPlaybackDevice.Read();
88#ifdef EXPERIMENTAL_MIDI_IN
89 mRecordDevice = MIDIRecordingDevice.Read();
90#endif
91// mRecordChannels = gPrefs->Read(wxT("/MidiIO/RecordChannels"), 2L);
92
93 //------------------------- Main section --------------------
94 // Now construct the GUI itself.
95 // Use 'eIsCreatingFromPrefs' so that the GUI is
96 // initialised with values from gPrefs.
98 PopulateOrExchange(S);
99 // ----------------------- End of main section --------------
100
101 wxCommandEvent e;
102 OnHost(e);
103}
104
109void MidiIOPrefs::GetNamesAndLabels() {
110 // Gather list of hosts. Only added hosts that have devices attached.
111 Pm_Terminate(); // close and open to refresh device lists
112 Pm_Initialize();
113 int nDevices = Pm_CountDevices();
114 for (int i = 0; i < nDevices; i++) {
115 const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
116 if (info->output || info->input) { //should always happen
117 wxString name = wxSafeConvertMB2WX(info->interf);
118 if (!make_iterator_range(mHostNames)
119 .contains( Verbatim( name ) )) {
120 mHostNames.push_back( Verbatim( name ) );
121 mHostLabels.push_back(name);
122 }
123 }
124 }
125
126 if (nDevices == 0) {
127 mHostNames.push_back(XO("No MIDI interfaces"));
128 mHostLabels.push_back(wxT("No MIDI interfaces"));
129 }
130}
131
132void MidiIOPrefs::PopulateOrExchange( ShuttleGui & S )
133{
134 ChoiceSetting Setting{ L"/MidiIO/Host",
135 { ByColumns, mHostNames, mHostLabels }
136 };
137
138 S.SetBorder(2);
139 S.StartScroller();
140
141 /* i18n-hint Software interface to MIDI */
142 S.StartStatic(XC("Interface", "MIDI"));
143 {
144 S.StartMultiColumn(2);
145 {
146 S.Id(HostID);
147 /* i18n-hint: (noun) */
148 mHost = S.TieChoice(XXO("&Host:"), Setting);
149
150 S.AddPrompt(XXO("Using: PortMidi"));
151 }
152 S.EndMultiColumn();
153 }
154 S.EndStatic();
155
156 S.StartStatic(XO("Playback"));
157 {
158 S.StartMultiColumn(2);
159 {
160 S.Id(PlayID);
161 mPlay = S.AddChoice(XXO("&Device:"),
162 {} );
163 mLatency = S.TieIntegerTextBox(XXO("MIDI Synth L&atency (ms):"),
165 }
166 S.EndMultiColumn();
167 }
168 S.EndStatic();
169#ifdef EXPERIMENTAL_MIDI_IN
170 S.StartStatic(XO("Recording"));
171 {
172 S.StartMultiColumn(2);
173 {
174 S.Id(RecordID);
175 mRecord = S.AddChoice(XO("De&vice:"),
176 {} );
177
178 S.Id(ChannelsID);
179 /*
180 mChannels = S.AddChoice(XO("&Channels:"),
181 wxEmptyString,
182 {} );
183 */
184 }
185 S.EndMultiColumn();
186 }
187 S.EndStatic();
188#endif
189 S.EndScroller();
190
191}
192
193void MidiIOPrefs::OnHost(wxCommandEvent & WXUNUSED(e))
194{
195 wxString itemAtIndex;
196 int index = mHost->GetCurrentSelection();
197 if (index >= 0 && index < (int)mHostNames.size())
198 itemAtIndex = mHostLabels[index];
199 int nDevices = Pm_CountDevices();
200
201 mPlay->Clear();
202#ifdef EXPERIMENTAL_MIDI_IN
203 mRecord->Clear();
204#endif
205
206 wxArrayStringEx playnames;
207 wxArrayStringEx recordnames;
208
209 for (int i = 0; i < nDevices; i++) {
210 const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
211 wxString interf = wxSafeConvertMB2WX(info->interf);
212 if (itemAtIndex == interf) {
213 wxString name = wxSafeConvertMB2WX(info->name);
214 wxString device = wxString::Format(wxT("%s: %s"),
215 interf,
216 name);
217 if (info->output) {
218 playnames.push_back(name);
219 index = mPlay->Append(name, (void *) info);
220 if (device == mPlayDevice) {
221 mPlay->SetSelection(index);
222 }
223 }
224#ifdef EXPERIMENTAL_MIDI_IN
225 if (info->input) {
226 recordnames.push_back(name);
227 index = mRecord->Append(name, (void *) info);
228 if (device == mRecordDevice) {
229 mRecord->SetSelection(index);
230 }
231 }
232#endif
233 }
234 }
235
236 if (mPlay->GetCount() == 0) {
237 playnames.push_back(_("No devices found"));
238 mPlay->Append(playnames[0], (void *) NULL);
239 }
240#ifdef EXPERIMENTAL_MIDI_IN
241 if (mRecord->GetCount() == 0) {
242 recordnames.push_back(_("No devices found"));
243 mRecord->Append(recordnames[0], (void *) NULL);
244 }
245#endif
246 if (mPlay->GetCount() && mPlay->GetSelection() == wxNOT_FOUND) {
247 mPlay->SetSelection(0);
248 }
249#ifdef EXPERIMENTAL_MIDI_IN
250 if (mRecord->GetCount() && mRecord->GetSelection() == wxNOT_FOUND) {
251 mRecord->SetSelection(0);
252 }
253#endif
254 ShuttleGui::SetMinSize(mPlay, playnames);
255#ifdef EXPERIMENTAL_MIDI_IN
256 ShuttleGui::SetMinSize(mRecord, recordnames);
257#endif
258// OnDevice(e);
259}
260
261bool MidiIOPrefs::Commit()
262{
264 PopulateOrExchange(S);
265
266 const PmDeviceInfo *info;
267
268 info = (const PmDeviceInfo *) mPlay->GetClientData(mPlay->GetSelection());
269 if (info) {
271 wxString::Format(wxT("%s: %s"),
272 wxString(wxSafeConvertMB2WX(info->interf)),
273 wxString(wxSafeConvertMB2WX(info->name))));
274 }
275#ifdef EXPERIMENTAL_MIDI_IN
276 info = (const PmDeviceInfo *) mRecord->GetClientData(mRecord->GetSelection());
277 if (info) {
278 MidiRecordingDevice.Write(
279 wxString::Format(wxT("%s: %s"),
280 wxString(wxSafeConvertMB2WX(info->interf)),
281 wxString(wxSafeConvertMB2WX(info->name))));
282 }
283#endif
285 return gPrefs->Flush();
286}
287
288bool MidiIOPrefs::Validate()
289{
290 long latency;
291 if (!mLatency->GetValue().ToLong(&latency)) {
293"The MIDI Synthesizer Latency must be an integer") );
294 return false;
295 }
296 return true;
297}
298
299#ifdef EXPERIMENTAL_MIDI_OUT
300namespace{
302 [](wxWindow *parent, wxWindowID winid, AudacityProject *)
303 {
304 wxASSERT(parent); // to justify safenew
305 return safenew MidiIOPrefs(parent, winid);
306 },
307 false,
308 // Register with an explicit ordering hint because this one is
309 // only conditionally compiled
310 { "", { Registry::OrderingHint::After, "Recording" } }
311};
312}
313#endif
314
315#endif
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
@ ChannelsID
Definition: DevicePrefs.cpp:57
@ HostID
Definition: DevicePrefs.cpp:54
@ RecordID
Definition: DevicePrefs.cpp:56
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
@ PlayID
Definition: ImportRaw.cpp:282
#define XC(s, c)
Definition: Internat.h:37
#define _(s)
Definition: Internat.h:73
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: IteratorX.h:210
#define safenew
Definition: MemoryX.h:9
IntSetting MIDISynthLatency_ms
Definition: NoteTrack.cpp:1012
StringSetting MIDIRecordingDevice
Definition: NoteTrack.cpp:1011
StringSetting MIDIPlaybackDevice
Definition: NoteTrack.cpp:1010
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
ByColumns_t ByColumns
Definition: Prefs.cpp:515
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:46
@ eIsSavingToPrefs
Definition: ShuttleGui.h:47
#define S(N)
Definition: ToChars.cpp:64
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
A PrefsPanel used to select recording and playback devices and other settings.
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
Definition: PrefsPanel.h:51
Definition: Prefs.h:178
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:259
void Invalidate() override
Definition: Prefs.h:289
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:207
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
static void SetMinSize(wxWindow *window, const TranslatableStrings &items)
Holds a msgid for the translation catalog; may also bind format arguments.
virtual bool Flush() noexcept=0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.