iPlug2 - C++ Audio Plug-in Framework
IPlugAPP_dialog.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5 
6  See LICENSE.txt for more info.
7 
8  ==============================================================================
9 */
10 
11 #include "IPlugAPP_host.h"
12 #include "config.h"
13 #include "resource.h"
14 
15 #ifdef OS_WIN
16 #include "asio.h"
17 #define GET_MENU() GetMenu(gHWND)
18 #elif defined OS_MAC
19 #define GET_MENU() SWELL_GetCurrentMenu()
20 #endif
21 
22 using namespace iplug;
23 
24 #if !defined NO_IGRAPHICS
25 #include "IGraphics.h"
26 using namespace igraphics;
27 #endif
28 
29 #if defined OS_MAC
30 extern int GetTitleBarOffset();
31 #endif
32 
33 // check the input and output devices, find matching srs
34 void IPlugAPPHost::PopulateSampleRateList(HWND hwndDlg, RtAudio::DeviceInfo* inputDevInfo, RtAudio::DeviceInfo* outputDevInfo)
35 {
36  WDL_String buf;
37 
38  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_SR,CB_RESETCONTENT,0,0);
39 
40  std::vector<int> matchedSRs;
41 
42  if (inputDevInfo->probed && outputDevInfo->probed)
43  {
44  for (int i=0; i<inputDevInfo->sampleRates.size(); i++)
45  {
46  for (int j=0; j<outputDevInfo->sampleRates.size(); j++)
47  {
48  if(inputDevInfo->sampleRates[i] == outputDevInfo->sampleRates[j])
49  matchedSRs.push_back(inputDevInfo->sampleRates[i]);
50  }
51  }
52  }
53 
54  for (int k=0; k<matchedSRs.size(); k++)
55  {
56  buf.SetFormatted(20, "%i", matchedSRs[k]);
57  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_SR,CB_ADDSTRING,0,(LPARAM)buf.Get());
58  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_SR,CB_SETITEMDATA,k,(LPARAM)matchedSRs[k]);
59  }
60 
61  WDL_String str;
62  str.SetFormatted(32, "%i", mState.mAudioSR);
63 
64  LRESULT sridx = SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_SR, CB_FINDSTRINGEXACT, -1, (LPARAM) str.Get());
65  SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_SR, CB_SETCURSEL, sridx, 0);
66 }
67 
68 void IPlugAPPHost::PopulateAudioInputList(HWND hwndDlg, RtAudio::DeviceInfo* info)
69 {
70  if(!info->probed)
71  return;
72 
73  WDL_String buf;
74 
75  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_L,CB_RESETCONTENT,0,0);
76  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_RESETCONTENT,0,0);
77 
78  int i;
79 
80  for (i=0; i<info->inputChannels -1; i++)
81  {
82  buf.SetFormatted(20, "%i", i+1);
83  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_L,CB_ADDSTRING,0,(LPARAM)buf.Get());
84  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_ADDSTRING,0,(LPARAM)buf.Get());
85  }
86 
87  // TEMP
88  buf.SetFormatted(20, "%i", i+1);
89  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_ADDSTRING,0,(LPARAM)buf.Get());
90 
91  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_L,CB_SETCURSEL, mState.mAudioInChanL - 1, 0);
92  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0);
93 }
94 
95 void IPlugAPPHost::PopulateAudioOutputList(HWND hwndDlg, RtAudio::DeviceInfo* info)
96 {
97  if(!info->probed)
98  return;
99 
100  WDL_String buf;
101 
102  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_L,CB_RESETCONTENT,0,0);
103  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_RESETCONTENT,0,0);
104 
105  int i;
106 
107  for (i=0; i<info->outputChannels -1; i++)
108  {
109  buf.SetFormatted(20, "%i", i+1);
110  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_L,CB_ADDSTRING,0,(LPARAM)buf.Get());
111  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_ADDSTRING,0,(LPARAM)buf.Get());
112  }
113 
114  // TEMP
115  buf.SetFormatted(20, "%i", i+1);
116  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_ADDSTRING,0,(LPARAM)buf.Get());
117 
118  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_L,CB_SETCURSEL, mState.mAudioOutChanL - 1, 0);
119  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0);
120 }
121 
122 // This has to get called after any change to audio driver/in dev/out dev
123 void IPlugAPPHost::PopulateDriverSpecificControls(HWND hwndDlg)
124 {
125 #ifdef OS_WIN
126  int driverType = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_DRIVER, CB_GETCURSEL, 0, 0);
127  if(driverType == kDeviceASIO)
128  {
129  ComboBox_Enable(GetDlgItem(hwndDlg, IDC_COMBO_AUDIO_IN_DEV), FALSE);
130  Button_Enable(GetDlgItem(hwndDlg, IDC_BUTTON_OS_DEV_SETTINGS), TRUE);
131  }
132  else
133  {
134  ComboBox_Enable(GetDlgItem(hwndDlg, IDC_COMBO_AUDIO_IN_DEV), TRUE);
135  Button_Enable(GetDlgItem(hwndDlg, IDC_BUTTON_OS_DEV_SETTINGS), FALSE);
136  }
137 #endif
138 
139  int indevidx = 0;
140  int outdevidx = 0;
141 
142  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_DEV,CB_RESETCONTENT,0,0);
143  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_DEV,CB_RESETCONTENT,0,0);
144 
145  for (int i = 0; i<mAudioInputDevs.size(); i++)
146  {
147  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_DEV,CB_ADDSTRING,0,(LPARAM)GetAudioDeviceName(mAudioInputDevs[i]).c_str());
148 
149  if(!strcmp(GetAudioDeviceName(mAudioInputDevs[i]).c_str(), mState.mAudioInDev.Get()))
150  indevidx = i;
151  }
152 
153  for (int i = 0; i<mAudioOutputDevs.size(); i++)
154  {
155  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_DEV,CB_ADDSTRING,0,(LPARAM)GetAudioDeviceName(mAudioOutputDevs[i]).c_str());
156 
157  if(!strcmp(GetAudioDeviceName(mAudioOutputDevs[i]).c_str(), mState.mAudioOutDev.Get()))
158  outdevidx = i;
159  }
160 
161 #ifdef OS_WIN
162  if(driverType == kDeviceASIO)
163  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_DEV,CB_SETCURSEL, outdevidx, 0);
164  else
165 #endif
166  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_DEV,CB_SETCURSEL, indevidx, 0);
167 
168  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_DEV,CB_SETCURSEL, outdevidx, 0);
169 
170  RtAudio::DeviceInfo inputDevInfo;
171  RtAudio::DeviceInfo outputDevInfo;
172 
173  if (mAudioInputDevs.size())
174  {
175  inputDevInfo = mDAC->getDeviceInfo(mAudioInputDevs[indevidx]);
176  PopulateAudioInputList(hwndDlg, &inputDevInfo);
177  }
178 
179  if (mAudioOutputDevs.size())
180  {
181  outputDevInfo = mDAC->getDeviceInfo(mAudioOutputDevs[outdevidx]);
182  PopulateAudioOutputList(hwndDlg, &outputDevInfo);
183  }
184 
185  PopulateSampleRateList(hwndDlg, &inputDevInfo, &outputDevInfo);
186 }
187 
188 void IPlugAPPHost::PopulateAudioDialogs(HWND hwndDlg)
189 {
190  PopulateDriverSpecificControls(hwndDlg);
191 
192 // if (mState.mAudioInIsMono)
193 // {
194 // SendDlgItemMessage(hwndDlg,IDC_CB_MONO_INPUT,BM_SETCHECK, BST_CHECKED,0);
195 // }
196 // else
197 // {
198 // SendDlgItemMessage(hwndDlg,IDC_CB_MONO_INPUT,BM_SETCHECK, BST_UNCHECKED,0);
199 // }
200 
201 // Populate buffer size combobox
202  for (int i = 0; i< kNumBufferSizeOptions; i++)
203  {
204  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_BUF_SIZE,CB_ADDSTRING,0,(LPARAM)kBufferSizeOptions[i].c_str());
205  }
206 
207  WDL_String str;
208  str.SetFormatted(32, "%i", mState.mBufferSize);
209 
210  LRESULT iovsidx = SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_BUF_SIZE, CB_FINDSTRINGEXACT, -1, (LPARAM) str.Get());
211  SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_BUF_SIZE, CB_SETCURSEL, iovsidx, 0);
212 }
213 
214 bool IPlugAPPHost::PopulateMidiDialogs(HWND hwndDlg)
215 {
216  if ( !mMidiIn || !mMidiOut )
217  return false;
218  else
219  {
220  for (int i=0; i<mMidiInputDevNames.size(); i++ )
221  {
222  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_IN_DEV,CB_ADDSTRING,0,(LPARAM)mMidiInputDevNames[i].c_str());
223  }
224 
225  LRESULT indevidx = SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_IN_DEV,CB_FINDSTRINGEXACT, -1, (LPARAM)mState.mMidiInDev.Get());
226 
227  // if the midi port name wasn't found update the ini file, and set to off
228  if(indevidx == -1)
229  {
230  mState.mMidiInDev.Set("off");
231  UpdateINI();
232  indevidx = 0;
233  }
234 
235  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_IN_DEV,CB_SETCURSEL, indevidx, 0);
236 
237  for (int i=0; i<mMidiOutputDevNames.size(); i++ )
238  {
239  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_OUT_DEV,CB_ADDSTRING,0,(LPARAM)mMidiOutputDevNames[i].c_str());
240  }
241 
242  LRESULT outdevidx = SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_OUT_DEV,CB_FINDSTRINGEXACT, -1, (LPARAM)mState.mMidiOutDev.Get());
243 
244  // if the midi port name wasn't found update the ini file, and set to off
245  if(outdevidx == -1)
246  {
247  mState.mMidiOutDev.Set("off");
248  UpdateINI();
249  outdevidx = 0;
250  }
251 
252  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_OUT_DEV,CB_SETCURSEL, outdevidx, 0);
253 
254  // Populate MIDI channel dialogs
255 
256  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_IN_CHAN,CB_ADDSTRING,0,(LPARAM)"all");
257  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_OUT_CHAN,CB_ADDSTRING,0,(LPARAM)"all");
258 
259  WDL_String buf;
260 
261  for (int i=0; i<16; i++)
262  {
263  buf.SetFormatted(20, "%i", i+1);
264  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_IN_CHAN,CB_ADDSTRING,0,(LPARAM)buf.Get());
265  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_OUT_CHAN,CB_ADDSTRING,0,(LPARAM)buf.Get());
266  }
267 
268  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_IN_CHAN,CB_SETCURSEL, (LPARAM)mState.mMidiInChan, 0);
269  SendDlgItemMessage(hwndDlg,IDC_COMBO_MIDI_OUT_CHAN,CB_SETCURSEL, (LPARAM)mState.mMidiOutChan, 0);
270 
271  return true;
272  }
273 }
274 
275 #ifdef OS_WIN
276 void IPlugAPPHost::PopulatePreferencesDialog(HWND hwndDlg)
277 {
278  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_DRIVER,CB_ADDSTRING,0,(LPARAM)"DirectSound");
279  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_DRIVER,CB_ADDSTRING,0,(LPARAM)"ASIO");
280  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_DRIVER,CB_SETCURSEL, mState.mAudioDriverType, 0);
281 
282  PopulateAudioDialogs(hwndDlg);
283  PopulateMidiDialogs(hwndDlg);
284 }
285 
286 #elif defined OS_MAC
287 void IPlugAPPHost::PopulatePreferencesDialog(HWND hwndDlg)
288 {
289  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_DRIVER,CB_ADDSTRING,0,(LPARAM)"CoreAudio");
290  //SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_DRIVER,CB_ADDSTRING,0,(LPARAM)"Jack");
291  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_DRIVER,CB_SETCURSEL, mState.mAudioDriverType, 0);
292 
293  PopulateAudioDialogs(hwndDlg);
294  PopulateMidiDialogs(hwndDlg);
295 }
296 #else
297  #error NOT IMPLEMENTED
298 #endif
299 
300 WDL_DLGRET IPlugAPPHost::PreferencesDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
301 {
302  IPlugAPPHost* _this = sInstance.get();
303  AppState& mState = _this->mState;
304  AppState& mTempState = _this->mTempState;
305  AppState& mActiveState = _this->mActiveState;
306 
307  auto getComboString = [&](WDL_String& str, int item, WPARAM idx) {
308  std::string tempString;
309  long len = (long) SendDlgItemMessage(hwndDlg, item, CB_GETLBTEXTLEN, idx, 0) + 1;
310  tempString.reserve(len);
311  SendDlgItemMessage(hwndDlg, item, CB_GETLBTEXT, idx, (LPARAM) tempString.data());
312  str.Set(tempString.c_str());
313  };
314 
315  int v = 0;
316  switch(uMsg)
317  {
318  case WM_INITDIALOG:
319  _this->PopulatePreferencesDialog(hwndDlg);
320  mTempState = mState;
321 
322  return TRUE;
323 
324  case WM_COMMAND:
325  switch (LOWORD(wParam))
326  {
327  case IDOK:
328  if(mActiveState != mState)
329  _this->TryToChangeAudio();
330 
331  EndDialog(hwndDlg, IDOK); // INI file will be changed see MainDialogProc
332  break;
333  case IDAPPLY:
334  _this->TryToChangeAudio();
335  break;
336  case IDCANCEL:
337  EndDialog(hwndDlg, IDCANCEL);
338 
339  // if state has been changed reset to previous state, INI file won't be changed
340  if (!_this->AudioSettingsInStateAreEqual(mState, mTempState)
341  || !_this->MIDISettingsInStateAreEqual(mState, mTempState))
342  {
343  mState = mTempState;
344 
345  _this->TryToChangeAudioDriverType();
346  _this->ProbeAudioIO();
347  _this->TryToChangeAudio();
348  }
349 
350  break;
351 
352  case IDC_COMBO_AUDIO_DRIVER:
353  if (HIWORD(wParam) == CBN_SELCHANGE)
354  {
355  v = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_DRIVER, CB_GETCURSEL, 0, 0);
356 
357  if(v != mState.mAudioDriverType)
358  {
359  mState.mAudioDriverType = v;
360 
361  _this->TryToChangeAudioDriverType();
362  _this->ProbeAudioIO();
363 
364  if (_this->mAudioInputDevs.size())
365  mState.mAudioInDev.Set(_this->GetAudioDeviceName(_this->mAudioInputDevs[0]).c_str());
366 
367  if (_this->mAudioOutputDevs.size())
368  mState.mAudioOutDev.Set(_this->GetAudioDeviceName(_this->mAudioOutputDevs[0]).c_str());
369 
370  // Reset IO
371  mState.mAudioOutChanL = 1;
372  mState.mAudioOutChanR = 2;
373 
374  _this->PopulateAudioDialogs(hwndDlg);
375  }
376  }
377  break;
378 
379  case IDC_COMBO_AUDIO_IN_DEV:
380  if (HIWORD(wParam) == CBN_SELCHANGE)
381  {
382  int idx = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_IN_DEV, CB_GETCURSEL, 0, 0);
383  getComboString(mState.mAudioInDev, IDC_COMBO_AUDIO_IN_DEV, idx);
384 
385  // Reset IO
386  mState.mAudioInChanL = 1;
387  mState.mAudioInChanR = 2;
388 
389  _this->PopulateDriverSpecificControls(hwndDlg);
390  }
391  break;
392 
393  case IDC_COMBO_AUDIO_OUT_DEV:
394  if (HIWORD(wParam) == CBN_SELCHANGE)
395  {
396  int idx = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_OUT_DEV, CB_GETCURSEL, 0, 0);
397  getComboString(mState.mAudioOutDev, IDC_COMBO_AUDIO_OUT_DEV, idx);
398 
399  // Reset IO
400  mState.mAudioOutChanL = 1;
401  mState.mAudioOutChanR = 2;
402 
403  _this->PopulateDriverSpecificControls(hwndDlg);
404  }
405  break;
406 
407  case IDC_COMBO_AUDIO_IN_L:
408  if (HIWORD(wParam) == CBN_SELCHANGE)
409  {
410  mState.mAudioInChanL = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_IN_L, CB_GETCURSEL, 0, 0) + 1;
411 
412  //TEMP
413  mState.mAudioInChanR = mState.mAudioInChanL + 1;
414  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0);
415  //
416  }
417  break;
418 
419  case IDC_COMBO_AUDIO_IN_R:
420  if (HIWORD(wParam) == CBN_SELCHANGE)
421  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_IN_R,CB_SETCURSEL, mState.mAudioInChanR - 1, 0); // TEMP
422  mState.mAudioInChanR = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_IN_R, CB_GETCURSEL, 0, 0);
423  break;
424 
425  case IDC_COMBO_AUDIO_OUT_L:
426  if (HIWORD(wParam) == CBN_SELCHANGE)
427  {
428  mState.mAudioOutChanL = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_OUT_L, CB_GETCURSEL, 0, 0) + 1;
429 
430  //TEMP
431  mState.mAudioOutChanR = mState.mAudioOutChanL + 1;
432  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0);
433  //
434  }
435  break;
436 
437  case IDC_COMBO_AUDIO_OUT_R:
438  if (HIWORD(wParam) == CBN_SELCHANGE)
439  SendDlgItemMessage(hwndDlg,IDC_COMBO_AUDIO_OUT_R,CB_SETCURSEL, mState.mAudioOutChanR - 1, 0); // TEMP
440  mState.mAudioOutChanR = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_OUT_R, CB_GETCURSEL, 0, 0);
441  break;
442 
443 // case IDC_CB_MONO_INPUT:
444 // if (SendDlgItemMessage(hwndDlg,IDC_CB_MONO_INPUT, BM_GETCHECK, 0, 0) == BST_CHECKED)
445 // mState.mAudioInIsMono = 1;
446 // else
447 // mState.mAudioInIsMono = 0;
448 // break;
449 
450  case IDC_COMBO_AUDIO_BUF_SIZE: // follow through
451  if (HIWORD(wParam) == CBN_SELCHANGE)
452  {
453  int iovsidx = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_BUF_SIZE, CB_GETCURSEL, 0, 0);
454  mState.mBufferSize = atoi(kBufferSizeOptions[iovsidx].c_str());
455  }
456  break;
457  case IDC_COMBO_AUDIO_SR:
458  if (HIWORD(wParam) == CBN_SELCHANGE)
459  {
460  int idx = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_SR, CB_GETCURSEL, 0, 0);
461  mState.mAudioSR = (uint32_t) SendDlgItemMessage(hwndDlg, IDC_COMBO_AUDIO_SR, CB_GETITEMDATA, idx, 0);
462  }
463  break;
464 
465  case IDC_BUTTON_OS_DEV_SETTINGS:
466  if (HIWORD(wParam) == BN_CLICKED)
467  #ifdef OS_WIN
468  if( (_this->mState.mAudioDriverType == kDeviceASIO) && (_this->mDAC->isStreamRunning() == true)) // TODO: still not right
469  ASIOControlPanel();
470  #elif defined OS_MAC
471  system("open \"/Applications/Utilities/Audio MIDI Setup.app\"");
472  #else
473  #error NOT IMPLEMENTED
474  #endif
475  break;
476 
477  case IDC_COMBO_MIDI_IN_DEV:
478  if (HIWORD(wParam) == CBN_SELCHANGE)
479  {
480  int idx = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_MIDI_IN_DEV, CB_GETCURSEL, 0, 0);
481  getComboString(mState.mMidiInDev, IDC_COMBO_MIDI_IN_DEV, idx);
482  _this->SelectMIDIDevice(ERoute::kInput, mState.mMidiInDev.Get());
483  }
484  break;
485 
486  case IDC_COMBO_MIDI_OUT_DEV:
487  if (HIWORD(wParam) == CBN_SELCHANGE)
488  {
489  int idx = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_MIDI_OUT_DEV, CB_GETCURSEL, 0, 0);
490  getComboString(mState.mMidiOutDev, IDC_COMBO_MIDI_OUT_DEV, idx);
491  _this->SelectMIDIDevice(ERoute::kOutput, mState.mMidiOutDev.Get());
492  }
493  break;
494 
495  case IDC_COMBO_MIDI_IN_CHAN:
496  if (HIWORD(wParam) == CBN_SELCHANGE)
497  mState.mMidiInChan = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_MIDI_IN_CHAN, CB_GETCURSEL, 0, 0);
498  break;
499 
500  case IDC_COMBO_MIDI_OUT_CHAN:
501  if (HIWORD(wParam) == CBN_SELCHANGE)
502  mState.mMidiOutChan = (int) SendDlgItemMessage(hwndDlg, IDC_COMBO_MIDI_OUT_CHAN, CB_GETCURSEL, 0, 0);
503  break;
504 
505  default:
506  break;
507  }
508  break;
509  default:
510  return FALSE;
511  }
512  return TRUE;
513 }
514 
515 static void ClientResize(HWND hWnd, int nWidth, int nHeight)
516 {
517  RECT rcClient, rcWindow;
518  POINT ptDiff;
519  int screenwidth, screenheight;
520  int x, y;
521 
522  screenwidth = GetSystemMetrics(SM_CXSCREEN);
523  screenheight = GetSystemMetrics(SM_CYSCREEN);
524  x = (screenwidth / 2) - (nWidth / 2);
525  y = (screenheight / 2) - (nHeight / 2);
526 
527  GetClientRect(hWnd, &rcClient);
528  GetWindowRect(hWnd, &rcWindow);
529 
530  ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
531  ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
532 
533  SetWindowPos(hWnd, 0, x, y, nWidth + ptDiff.x, nHeight + ptDiff.y, 0);
534 }
535 
536 #ifdef OS_WIN
537 extern float GetScaleForHWND(HWND hWnd);
538 #endif
539 
540 //static
541 WDL_DLGRET IPlugAPPHost::MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
542 {
543  IPlugAPPHost* pAppHost = IPlugAPPHost::sInstance.get();
544 
545  int width = 0;
546  int height = 0;
547 
548  switch (uMsg)
549  {
550  case WM_INITDIALOG:
551  {
552  gHWND = hwndDlg;
553  IPlugAPP* pPlug = pAppHost->GetPlug();
554 
555  if (!pAppHost->OpenWindow(gHWND))
556  DBGMSG("couldn't attach gui\n");
557 
558  width = pPlug->GetEditorWidth();
559  height = pPlug->GetEditorHeight();
560 
561  ClientResize(hwndDlg, width, height);
562 
563  ShowWindow(hwndDlg, SW_SHOW);
564  return 1;
565  }
566  case WM_DESTROY:
567  pAppHost->CloseWindow();
568  gHWND = NULL;
569  IPlugAPPHost::sInstance = nullptr;
570 
571  #ifdef OS_WIN
572  PostQuitMessage(0);
573  #else
574  SWELL_PostQuitMessage(hwndDlg);
575  #endif
576 
577  return 0;
578  case WM_CLOSE:
579  DestroyWindow(hwndDlg);
580  return 0;
581  case WM_COMMAND:
582  switch (LOWORD(wParam))
583  {
584  case ID_QUIT:
585  {
586  DestroyWindow(hwndDlg);
587  return 0;
588  }
589  case ID_ABOUT:
590  {
591  IPlugAPP* pPlug = pAppHost->GetPlug();
592 
593  bool pluginOpensAboutBox = pPlug->OnHostRequestingAboutBox();
594 
595  if (pluginOpensAboutBox == false)
596  {
597  WDL_String info;
598  info.Append(PLUG_COPYRIGHT_STR"\nBuilt on " __DATE__);
599  MessageBox(hwndDlg, info.Get(), PLUG_NAME, MB_OK);
600  }
601 
602  return 0;
603  }
604  case ID_HELP:
605  {
606  IPlugAPP* pPlug = pAppHost->GetPlug();
607 
608  bool pluginOpensHelp = pPlug->OnHostRequestingProductHelp();
609 
610  if (pluginOpensHelp == false)
611  {
612  MessageBox(hwndDlg, "See the manual", PLUG_NAME, MB_OK);
613  }
614  return 0;
615  }
616  case ID_PREFERENCES:
617  {
618  INT_PTR ret = DialogBox(gHINSTANCE, MAKEINTRESOURCE(IDD_DIALOG_PREF), hwndDlg, IPlugAPPHost::PreferencesDlgProc);
619 
620  if(ret == IDOK)
621  pAppHost->UpdateINI();
622 
623  return 0;
624  }
625 #if defined _DEBUG && !defined NO_IGRAPHICS
626  case ID_LIVE_EDIT:
627  {
628  IGEditorDelegate* pPlug = dynamic_cast<IGEditorDelegate*>(pAppHost->GetPlug());
629 
630  if(pPlug)
631  {
632  IGraphics* pGraphics = pPlug->GetUI();
633 
634  if(pGraphics)
635  {
636  bool enabled = pGraphics->LiveEditEnabled();
637  pGraphics->EnableLiveEdit(!enabled);
638  CheckMenuItem(GET_MENU(), ID_LIVE_EDIT, (MF_BYCOMMAND | enabled) ? MF_UNCHECKED : MF_CHECKED);
639  }
640  }
641 
642  return 0;
643  }
644  case ID_SHOW_DRAWN:
645  {
646  IGEditorDelegate* pPlug = dynamic_cast<IGEditorDelegate*>(pAppHost->GetPlug());
647 
648  if(pPlug)
649  {
650  IGraphics* pGraphics = pPlug->GetUI();
651 
652  if(pGraphics)
653  {
654  bool enabled = pGraphics->ShowAreaDrawnEnabled();
655  pGraphics->ShowAreaDrawn(!enabled);
656  CheckMenuItem(GET_MENU(), ID_SHOW_DRAWN, (MF_BYCOMMAND | enabled) ? MF_UNCHECKED : MF_CHECKED);
657  }
658  }
659 
660  return 0;
661  }
662  case ID_SHOW_BOUNDS:
663  {
664  IGEditorDelegate* pPlug = dynamic_cast<IGEditorDelegate*>(pAppHost->GetPlug());
665 
666  if(pPlug)
667  {
668  IGraphics* pGraphics = pPlug->GetUI();
669 
670  if(pGraphics)
671  {
672  bool enabled = pGraphics->ShowControlBoundsEnabled();
673  pGraphics->ShowControlBounds(!enabled);
674  CheckMenuItem(GET_MENU(), ID_SHOW_BOUNDS, (MF_BYCOMMAND | enabled) ? MF_UNCHECKED : MF_CHECKED);
675  }
676  }
677 
678  return 0;
679  }
680  case ID_SHOW_FPS:
681  {
682  IGEditorDelegate* pPlug = dynamic_cast<IGEditorDelegate*>(pAppHost->GetPlug());
683 
684  if(pPlug)
685  {
686  IGraphics* pGraphics = pPlug->GetUI();
687 
688  if(pGraphics)
689  {
690  bool enabled = pGraphics->ShowingFPSDisplay();
691  pGraphics->ShowFPSDisplay(!enabled);
692  CheckMenuItem(GET_MENU(), ID_SHOW_FPS, (MF_BYCOMMAND | enabled) ? MF_UNCHECKED : MF_CHECKED);
693  }
694  }
695 
696  return 0;
697  }
698 #endif
699  }
700  return 0;
701  case WM_GETMINMAXINFO:
702  {
703  if(!pAppHost)
704  return 1;
705 
706  IPlugAPP* pPlug = pAppHost->GetPlug();
707 
708  MINMAXINFO* mmi = (MINMAXINFO*) lParam;
709  mmi->ptMinTrackSize.x = pPlug->GetMinWidth();
710  mmi->ptMinTrackSize.y = pPlug->GetMinHeight();
711  mmi->ptMaxTrackSize.x = pPlug->GetMaxWidth();
712  mmi->ptMaxTrackSize.y = pPlug->GetMaxHeight();
713 
714 #ifdef OS_MAC
715  const int titleBarOffset = GetTitleBarOffset();
716  mmi->ptMinTrackSize.y += titleBarOffset;
717  mmi->ptMaxTrackSize.y += titleBarOffset;
718 #endif
719 
720 #ifdef OS_WIN
721  float scale = GetScaleForHWND(hwndDlg);
722  mmi->ptMinTrackSize.x = static_cast<LONG>(static_cast<float>(mmi->ptMinTrackSize.x) * scale);
723  mmi->ptMinTrackSize.y = static_cast<LONG>(static_cast<float>(mmi->ptMinTrackSize.y) * scale);
724  mmi->ptMaxTrackSize.x = static_cast<LONG>(static_cast<float>(mmi->ptMaxTrackSize.x) * scale);
725  mmi->ptMaxTrackSize.y = static_cast<LONG>(static_cast<float>(mmi->ptMaxTrackSize.y) * scale);
726 #endif
727 
728  return 0;
729  }
730 #ifdef OS_WIN
731  case WM_DPICHANGED:
732  {
733  WORD dpi = HIWORD(wParam);
734  RECT* rect = (RECT*)lParam;
735  float scale = GetScaleForHWND(hwndDlg);
736 
737  POINT ptDiff;
738  RECT rcClient;
739  RECT rcWindow;
740 
741  GetClientRect(hwndDlg, &rcClient);
742  GetWindowRect(hwndDlg, &rcWindow);
743 
744  ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
745  ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
746 
747 #ifndef NO_IGRAPHICS
748  IGEditorDelegate* pPlug = dynamic_cast<IGEditorDelegate*>(pAppHost->GetPlug());
749 
750  if (pPlug)
751  {
752  IGraphics* pGraphics = pPlug->GetUI();
753 
754  if (pGraphics)
755  {
756  pGraphics->SetScreenScale(scale);
757  }
758  }
759 #else
760  IEditorDelegate* pPlug = dynamic_cast<IEditorDelegate*>(pAppHost->GetPlug());
761 #endif
762 
763  int w = pPlug->GetEditorWidth();
764  int h = pPlug->GetEditorHeight();
765 
766  SetWindowPos(hwndDlg, 0, rect->left, rect->top, w + ptDiff.x, h + ptDiff.y, 0);
767 
768  return 0;
769  }
770 #endif
771  case WM_SIZE:
772  {
773  IPlugAPP* pPlug = pAppHost->GetPlug();
774 
775  switch (LOWORD(wParam))
776  {
777  case SIZE_RESTORED:
778  case SIZE_MAXIMIZED:
779  {
780  RECT r;
781  GetClientRect(hwndDlg, &r);
782  float scale = 1.f;
783  #ifdef OS_WIN
784  scale = GetScaleForHWND(hwndDlg);
785  #endif
786  pPlug->OnParentWindowResize(static_cast<int>(r.right / scale), static_cast<int>(r.bottom / scale));
787  return 1;
788  }
789  default:
790  return 0;
791  }
792  }
793  }
794  return 0;
795 }
bool LiveEditEnabled() const
Definition: IGraphics.h:1149
void ShowAreaDrawn(bool enable)
Definition: IGraphics.h:1136
bool ShowAreaDrawnEnabled() const
Definition: IGraphics.h:1139
std::string GetAudioDeviceName(int idx) const
Returns the name of the audio device at idx.
Standalone application base class for an IPlug plug-in.
Definition: IPlugAPP.h:35
bool ShowControlBoundsEnabled() const
Definition: IGraphics.h:1142
void SetScreenScale(float scale)
Called by the platform IGraphics class when moving to a new screen to set DPI.
Definition: IGraphics.cpp:79
void ProbeAudioIO()
find out which devices have input channels & which have output channels, add their ids to the lists ...
The lowest level base class of an IGraphics context.
An editor delegate base class for a SOMETHING that uses IGraphics for it&#39;s UI.
void EnableLiveEdit(bool enable)
Live edit mode allows you to relocate controls at runtime in debug builds.
Definition: IGraphics.cpp:1506
int GetEditorWidth() const
The lowest level base class of an IGraphics context.
Definition: IGraphics.h:86
This pure virtual interface delegates communication in both directions between a UI editor and someth...
void ShowFPSDisplay(bool enable)
Shows a control to display the frame rate of drawing.
Definition: IGraphics.cpp:422
bool ShowingFPSDisplay()
Definition: IGraphics.h:1300
void ShowControlBounds(bool enable)
Definition: IGraphics.h:1133
int GetEditorHeight() const
A class that hosts an IPlug as a standalone app and provides Audio/Midi I/O.
Definition: IPlugAPP_host.h:81
IGraphics * GetUI()
Get a pointer to the IGraphics context.