iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugAPP_host.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
13#ifdef OS_WIN
14#include <sys/stat.h>
15#endif
16
17#include "IPlugLogger.h"
18
19using namespace iplug;
20
21#ifndef MAX_PATH_LEN
22#define MAX_PATH_LEN 2048
23#endif
24
25#define STRBUFSZ 100
26
27std::unique_ptr<IPlugAPPHost> IPlugAPPHost::sInstance;
28UINT gSCROLLMSG;
29
30IPlugAPPHost::IPlugAPPHost()
31: mIPlug(MakePlug(InstanceInfo{this}))
32{
33}
34
35IPlugAPPHost::~IPlugAPPHost()
36{
37 mExiting = true;
38
39 CloseAudio();
40
41 if(mMidiIn)
42 mMidiIn->cancelCallback();
43
44 if(mMidiOut)
45 mMidiOut->closePort();
46}
47
48//static
49IPlugAPPHost* IPlugAPPHost::Create()
50{
51 sInstance = std::make_unique<IPlugAPPHost>();
52 return sInstance.get();
53}
54
55bool IPlugAPPHost::Init()
56{
57 mIPlug->SetHost("standalone", mIPlug->GetPluginVersion(false));
58
59 if (!InitState())
60 return false;
61
62 TryToChangeAudioDriverType(); // will init RTAudio with an API type based on gState->mAudioDriverType
63 ProbeAudioIO(); // find out what audio IO devs are available and put their IDs in the global variables gAudioInputDevs / gAudioOutputDevs
64 InitMidi(); // creates RTMidiIn and RTMidiOut objects
65 ProbeMidiIO(); // find out what midi IO devs are available and put their names in the global variables gMidiInputDevs / gMidiOutputDevs
66 SelectMIDIDevice(ERoute::kInput, mState.mMidiInDev.Get());
67 SelectMIDIDevice(ERoute::kOutput, mState.mMidiOutDev.Get());
68
69 mIPlug->OnParamReset(kReset);
70 mIPlug->OnActivate(true);
71
72 return true;
73}
74
75bool IPlugAPPHost::OpenWindow(HWND pParent)
76{
77 return mIPlug->OpenWindow(pParent) != nullptr;
78}
79
80void IPlugAPPHost::CloseWindow()
81{
82 mIPlug->CloseWindow();
83}
84
85bool IPlugAPPHost::InitState()
86{
87#if defined OS_WIN
88 TCHAR strPath[MAX_PATH_LEN];
89 SHGetFolderPathA( NULL, CSIDL_LOCAL_APPDATA, NULL, 0, strPath );
90 mINIPath.SetFormatted(MAX_PATH_LEN, "%s\\%s\\", strPath, BUNDLE_NAME);
91#elif defined OS_MAC
92 mINIPath.SetFormatted(MAX_PATH_LEN, "%s/Library/Application Support/%s/", getenv("HOME"), BUNDLE_NAME);
93#else
94 #error NOT IMPLEMENTED
95#endif
96
97 struct stat st;
98
99 if(stat(mINIPath.Get(), &st) == 0) // if directory exists
100 {
101 mINIPath.Append("settings.ini"); // add file name to path
102
103 char buf[STRBUFSZ];
104
105 if(stat(mINIPath.Get(), &st) == 0) // if settings file exists read values into state
106 {
107 DBGMSG("Reading ini file from %s\n", mINIPath.Get());
108
109 mState.mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, mINIPath.Get());
110
111 GetPrivateProfileString("audio", "indev", "Built-in Input", buf, STRBUFSZ, mINIPath.Get()); mState.mAudioInDev.Set(buf);
112 GetPrivateProfileString("audio", "outdev", "Built-in Output", buf, STRBUFSZ, mINIPath.Get()); mState.mAudioOutDev.Set(buf);
113
114 //audio
115 mState.mAudioInChanL = GetPrivateProfileInt("audio", "in1", 1, mINIPath.Get()); // 1 is first audio input
116 mState.mAudioInChanR = GetPrivateProfileInt("audio", "in2", 2, mINIPath.Get());
117 mState.mAudioOutChanL = GetPrivateProfileInt("audio", "out1", 1, mINIPath.Get()); // 1 is first audio output
118 mState.mAudioOutChanR = GetPrivateProfileInt("audio", "out2", 2, mINIPath.Get());
119 //mState.mAudioInIsMono = GetPrivateProfileInt("audio", "monoinput", 0, mINIPath.Get());
120
121 mState.mBufferSize = GetPrivateProfileInt("audio", "buffer", 512, mINIPath.Get());
122 mState.mAudioSR = GetPrivateProfileInt("audio", "sr", 44100, mINIPath.Get());
123
124 //midi
125 GetPrivateProfileString("midi", "indev", "no input", buf, STRBUFSZ, mINIPath.Get()); mState.mMidiInDev.Set(buf);
126 GetPrivateProfileString("midi", "outdev", "no output", buf, STRBUFSZ, mINIPath.Get()); mState.mMidiOutDev.Set(buf);
127
128 mState.mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, mINIPath.Get()); // 0 is any
129 mState.mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, mINIPath.Get()); // 1 is first chan
130 }
131
132 // if settings file doesn't exist, populate with default values, otherwise overrwrite
133 UpdateINI();
134 }
135 else // folder doesn't exist - make folder and make file
136 {
137#if defined OS_WIN
138 // folder doesn't exist - make folder and make file
139 CreateDirectory(mINIPath.Get(), NULL);
140 mINIPath.Append("settings.ini");
141 UpdateINI(); // will write file if doesn't exist
142#elif defined OS_MAC
143 mode_t process_mask = umask(0);
144 int result_code = mkdir(mINIPath.Get(), S_IRWXU | S_IRWXG | S_IRWXO);
145 umask(process_mask);
146
147 if(!result_code)
148 {
149 mINIPath.Append("\\settings.ini");
150 UpdateINI(); // will write file if doesn't exist
151 }
152 else
153 {
154 return false;
155 }
156#else
157 #error NOT IMPLEMENTED
158#endif
159 }
160
161 return true;
162}
163
164void IPlugAPPHost::UpdateINI()
165{
166 char buf[STRBUFSZ]; // temp buffer for writing integers to profile strings
167 const char* ini = mINIPath.Get();
168
169 sprintf(buf, "%u", mState.mAudioDriverType);
170 WritePrivateProfileString("audio", "driver", buf, ini);
171
172 WritePrivateProfileString("audio", "indev", mState.mAudioInDev.Get(), ini);
173 WritePrivateProfileString("audio", "outdev", mState.mAudioOutDev.Get(), ini);
174
175 sprintf(buf, "%u", mState.mAudioInChanL);
176 WritePrivateProfileString("audio", "in1", buf, ini);
177 sprintf(buf, "%u", mState.mAudioInChanR);
178 WritePrivateProfileString("audio", "in2", buf, ini);
179 sprintf(buf, "%u", mState.mAudioOutChanL);
180 WritePrivateProfileString("audio", "out1", buf, ini);
181 sprintf(buf, "%u", mState.mAudioOutChanR);
182 WritePrivateProfileString("audio", "out2", buf, ini);
183 //sprintf(buf, "%u", mState.mAudioInIsMono);
184 //WritePrivateProfileString("audio", "monoinput", buf, ini);
185
186 WDL_String str;
187 str.SetFormatted(32, "%i", mState.mBufferSize);
188 WritePrivateProfileString("audio", "buffer", str.Get(), ini);
189
190 str.SetFormatted(32, "%i", mState.mAudioSR);
191 WritePrivateProfileString("audio", "sr", str.Get(), ini);
192
193 WritePrivateProfileString("midi", "indev", mState.mMidiInDev.Get(), ini);
194 WritePrivateProfileString("midi", "outdev", mState.mMidiOutDev.Get(), ini);
195
196 sprintf(buf, "%u", mState.mMidiInChan);
197 WritePrivateProfileString("midi", "inchan", buf, ini);
198 sprintf(buf, "%u", mState.mMidiOutChan);
199 WritePrivateProfileString("midi", "outchan", buf, ini);
200}
201
202std::string IPlugAPPHost::GetAudioDeviceName(int idx) const
203{
204 return mAudioIDDevNames.at(idx);
205}
206
207int IPlugAPPHost::GetAudioDeviceIdx(const char* deviceNameToTest) const
208{
209 for(int i = 0; i < mAudioIDDevNames.size(); i++)
210 {
211 if(!strcmp(deviceNameToTest, mAudioIDDevNames.at(i).c_str() ))
212 return i;
213 }
214
215 return -1;
216}
217
218int IPlugAPPHost::GetMIDIPortNumber(ERoute direction, const char* nameToTest) const
219{
220 int start = 1;
221
222 if(direction == ERoute::kInput)
223 {
224 if(!strcmp(nameToTest, OFF_TEXT)) return 0;
225
226 #ifdef OS_MAC
227 start = 2;
228 if(!strcmp(nameToTest, "virtual input")) return 1;
229 #endif
230
231 for (int i = 0; i < mMidiIn->getPortCount(); i++)
232 {
233 if(!strcmp(nameToTest, mMidiIn->getPortName(i).c_str()))
234 return (i + start);
235 }
236 }
237 else
238 {
239 if(!strcmp(nameToTest, OFF_TEXT)) return 0;
240
241 #ifdef OS_MAC
242 start = 2;
243 if(!strcmp(nameToTest, "virtual output")) return 1;
244 #endif
245
246 for (int i = 0; i < mMidiOut->getPortCount(); i++)
247 {
248 if(!strcmp(nameToTest, mMidiOut->getPortName(i).c_str()))
249 return (i + start);
250 }
251 }
252
253 return -1;
254}
255
257{
258 std::cout << "\nRtAudio Version " << RtAudio::getVersion() << std::endl;
259
260 RtAudio::DeviceInfo info;
261
262 mAudioInputDevs.clear();
263 mAudioOutputDevs.clear();
264 mAudioIDDevNames.clear();
265
266 uint32_t nDevices = mDAC->getDeviceCount();
267
268 for (int i=0; i<nDevices; i++)
269 {
270 info = mDAC->getDeviceInfo(i);
271 std::string deviceName = info.name;
272
273#ifdef OS_MAC
274 size_t colonIdx = deviceName.rfind(": ");
275
276 if(colonIdx != std::string::npos && deviceName.length() >= 2)
277 deviceName = deviceName.substr(colonIdx + 2, deviceName.length() - colonIdx - 2);
278
279#endif
280
281 mAudioIDDevNames.push_back(deviceName);
282
283 if ( info.probed == false )
284 std::cout << deviceName << ": Probe Status = Unsuccessful\n";
285 else if ( !strcmp("Generic Low Latency ASIO Driver", deviceName.c_str() ))
286 std::cout << deviceName << ": Probe Status = Unsuccessful\n";
287 else
288 {
289 if(info.inputChannels > 0)
290 mAudioInputDevs.push_back(i);
291
292 if(info.outputChannels > 0)
293 mAudioOutputDevs.push_back(i);
294
295 if (info.isDefaultInput)
296 mDefaultInputDev = i;
297
298 if (info.isDefaultOutput)
299 mDefaultOutputDev = i;
300 }
301 }
302}
303
304void IPlugAPPHost::ProbeMidiIO()
305{
306 if ( !mMidiIn || !mMidiOut )
307 return;
308 else
309 {
310 int nInputPorts = mMidiIn->getPortCount();
311
312 mMidiInputDevNames.push_back(OFF_TEXT);
313
314#ifdef OS_MAC
315 mMidiInputDevNames.push_back("virtual input");
316#endif
317
318 for (int i=0; i<nInputPorts; i++ )
319 {
320 mMidiInputDevNames.push_back(mMidiIn->getPortName(i));
321 }
322
323 int nOutputPorts = mMidiOut->getPortCount();
324
325 mMidiOutputDevNames.push_back(OFF_TEXT);
326
327#ifdef OS_MAC
328 mMidiOutputDevNames.push_back("virtual output");
329#endif
330
331 for (int i=0; i<nOutputPorts; i++ )
332 {
333 mMidiOutputDevNames.push_back(mMidiOut->getPortName(i));
334 //This means the virtual output port wont be added as an input
335 }
336 }
337}
338
339bool IPlugAPPHost::AudioSettingsInStateAreEqual(AppState& os, AppState& ns)
340{
341 if (os.mAudioDriverType != ns.mAudioDriverType) return false;
342 if (strcmp(os.mAudioInDev.Get(), ns.mAudioInDev.Get())) return false;
343 if (strcmp(os.mAudioOutDev.Get(), ns.mAudioOutDev.Get())) return false;
344 if (os.mAudioSR != ns.mAudioSR) return false;
345 if (os.mBufferSize != ns.mBufferSize) return false;
346 if (os.mAudioInChanL != ns.mAudioInChanL) return false;
347 if (os.mAudioInChanR != ns.mAudioInChanR) return false;
348 if (os.mAudioOutChanL != ns.mAudioOutChanL) return false;
349 if (os.mAudioOutChanR != ns.mAudioOutChanR) return false;
350// if (os.mAudioInIsMono != ns.mAudioInIsMono) return false;
351
352 return true;
353}
354
355bool IPlugAPPHost::MIDISettingsInStateAreEqual(AppState& os, AppState& ns)
356{
357 if (strcmp(os.mMidiInDev.Get(), ns.mMidiInDev.Get())) return false;
358 if (strcmp(os.mMidiOutDev.Get(), ns.mMidiOutDev.Get())) return false;
359 if (os.mMidiInChan != ns.mMidiInChan) return false;
360 if (os.mMidiOutChan != ns.mMidiOutChan) return false;
361
362 return true;
363}
364
365bool IPlugAPPHost::TryToChangeAudioDriverType()
366{
367 CloseAudio();
368
369 if (mDAC)
370 {
371 mDAC = nullptr;
372 }
373
374#if defined OS_WIN
375 if(mState.mAudioDriverType == kDeviceASIO)
376 mDAC = std::make_unique<RtAudio>(RtAudio::WINDOWS_ASIO);
377 else
378 mDAC = std::make_unique<RtAudio>(RtAudio::WINDOWS_DS);
379#elif defined OS_MAC
380 if(mState.mAudioDriverType == kDeviceCoreAudio)
381 mDAC = std::make_unique<RtAudio>(RtAudio::MACOSX_CORE);
382 //else
383 //mDAC = std::make_unique<RtAudio>(RtAudio::UNIX_JACK);
384#else
385 #error NOT IMPLEMENTED
386#endif
387
388 if(mDAC)
389 return true;
390 else
391 return false;
392}
393
394bool IPlugAPPHost::TryToChangeAudio()
395{
396 int inputID = -1;
397 int outputID = -1;
398
399#if defined OS_WIN
400 if(mState.mAudioDriverType == kDeviceASIO)
401 inputID = GetAudioDeviceIdx(mState.mAudioOutDev.Get());
402 else
403 inputID = GetAudioDeviceIdx(mState.mAudioInDev.Get());
404#elif defined OS_MAC
405 inputID = GetAudioDeviceIdx(mState.mAudioInDev.Get());
406#else
407 #error NOT IMPLEMENTED
408#endif
409 outputID = GetAudioDeviceIdx(mState.mAudioOutDev.Get());
410
411 bool failedToFindDevice = false;
412 bool resetToDefault = false;
413
414 if (inputID == -1)
415 {
416 if (mDefaultInputDev > -1)
417 {
418 resetToDefault = true;
419 inputID = mDefaultInputDev;
420
421 if (mAudioInputDevs.size())
422 mState.mAudioInDev.Set(GetAudioDeviceName(inputID).c_str());
423 }
424 else
425 failedToFindDevice = true;
426 }
427
428 if (outputID == -1)
429 {
430 if (mDefaultOutputDev > -1)
431 {
432 resetToDefault = true;
433
434 outputID = mDefaultOutputDev;
435
436 if (mAudioOutputDevs.size())
437 mState.mAudioOutDev.Set(GetAudioDeviceName(outputID).c_str());
438 }
439 else
440 failedToFindDevice = true;
441 }
442
443 if (resetToDefault)
444 {
445 DBGMSG("couldn't find previous audio device, reseting to default\n");
446
447 UpdateINI();
448 }
449
450 if (failedToFindDevice)
451 MessageBox(gHWND, "Please check your soundcard settings in Preferences", "Error", MB_OK);
452
453 if (inputID != -1 && outputID != -1)
454 {
455 return InitAudio(inputID, outputID, mState.mAudioSR, mState.mBufferSize);
456 }
457
458 return false;
459}
460
461bool IPlugAPPHost::SelectMIDIDevice(ERoute direction, const char* pPortName)
462{
463 int port = GetMIDIPortNumber(direction, pPortName);
464
465 if(direction == ERoute::kInput)
466 {
467 if(port == -1)
468 {
469 mState.mMidiInDev.Set(OFF_TEXT);
470 UpdateINI();
471 port = 0;
472 }
473
474 //TODO: send all notes off?
475 if (mMidiIn)
476 {
477 mMidiIn->closePort();
478
479 if (port == 0)
480 {
481 return true;
482 }
483 #if defined OS_WIN
484 else
485 {
486 mMidiIn->openPort(port-1);
487 return true;
488 }
489 #elif defined OS_MAC
490 else if(port == 1)
491 {
492 std::string virtualMidiInputName = "To ";
493 virtualMidiInputName += BUNDLE_NAME;
494 mMidiIn->openVirtualPort(virtualMidiInputName);
495 return true;
496 }
497 else
498 {
499 mMidiIn->openPort(port-2);
500 return true;
501 }
502 #else
503 #error NOT IMPLEMENTED
504 #endif
505 }
506 }
507 else
508 {
509 if(port == -1)
510 {
511 mState.mMidiOutDev.Set(OFF_TEXT);
512 UpdateINI();
513 port = 0;
514 }
515
516 if (mMidiOut)
517 {
518 //TODO: send all notes off?
519 mMidiOut->closePort();
520
521 if (port == 0)
522 return true;
523#if defined OS_WIN
524 else
525 {
526 mMidiOut->openPort(port-1);
527 return true;
528 }
529#elif defined OS_MAC
530 else if(port == 1)
531 {
532 std::string virtualMidiOutputName = "From ";
533 virtualMidiOutputName += BUNDLE_NAME;
534 mMidiOut->openVirtualPort(virtualMidiOutputName);
535 return true;
536 }
537 else
538 {
539 mMidiOut->openPort(port-2);
540 return true;
541 }
542#else
543 #error NOT IMPLEMENTED
544#endif
545 }
546 }
547
548 return false;
549}
550
551void IPlugAPPHost::CloseAudio()
552{
553 if (mDAC && mDAC->isStreamOpen())
554 {
555 if (mDAC->isStreamRunning())
556 {
557 mAudioEnding = true;
558
559 while (!mAudioDone)
560 Sleep(10);
561
562 try
563 {
564 mDAC->abortStream();
565 }
566 catch (RtAudioError& e)
567 {
568 e.printMessage();
569 }
570 }
571
572 mDAC->closeStream();
573 }
574}
575
576bool IPlugAPPHost::InitAudio(uint32_t inId, uint32_t outId, uint32_t sr, uint32_t iovs)
577{
578 CloseAudio();
579
580 RtAudio::StreamParameters iParams, oParams;
581 iParams.deviceId = inId;
582 iParams.nChannels = GetPlug()->MaxNChannels(ERoute::kInput); // TODO: flexible channel count
583 iParams.firstChannel = 0; // TODO: flexible channel count
584
585 oParams.deviceId = outId;
586 oParams.nChannels = GetPlug()->MaxNChannels(ERoute::kOutput); // TODO: flexible channel count
587 oParams.firstChannel = 0; // TODO: flexible channel count
588
589 mBufferSize = iovs; // mBufferSize may get changed by stream
590
591 DBGMSG("\ntrying to start audio stream @ %i sr, %i buffer size\nindev = %i:%s\noutdev = %i:%s\ninputs = %i\noutputs = %i\n",
592 sr, mBufferSize, inId, GetAudioDeviceName(inId).c_str(), outId, GetAudioDeviceName(outId).c_str(), iParams.nChannels, oParams.nChannels);
593
594 RtAudio::StreamOptions options;
595 options.flags = RTAUDIO_NONINTERLEAVED;
596 // options.streamName = BUNDLE_NAME; // JACK stream name, not used on other streams
597
598 mBufIndex = 0;
599 mSamplesElapsed = 0;
600 mSampleRate = (double) sr;
601 mVecWait = 0;
602 mAudioEnding = false;
603 mAudioDone = false;
604
605 mIPlug->SetBlockSize(APP_SIGNAL_VECTOR_SIZE);
606 mIPlug->SetSampleRate(mSampleRate);
607 mIPlug->OnReset();
608
609 try
610 {
611 mDAC->openStream(&oParams, iParams.nChannels > 0 ? &iParams : nullptr, RTAUDIO_FLOAT64, sr, &mBufferSize, &AudioCallback, this, &options /*, &ErrorCallback */);
612
613 for (int i = 0; i < iParams.nChannels; i++)
614 {
615 mInputBufPtrs.Add(nullptr); //will be set in callback
616 }
617
618 for (int i = 0; i < oParams.nChannels; i++)
619 {
620 mOutputBufPtrs.Add(nullptr); //will be set in callback
621 }
622
623 mDAC->startStream();
624
625 mActiveState = mState;
626 }
627 catch (RtAudioError& e)
628 {
629 e.printMessage();
630 return false;
631 }
632
633 return true;
634}
635
636bool IPlugAPPHost::InitMidi()
637{
638 try
639 {
640 mMidiIn = std::make_unique<RtMidiIn>();
641 }
642 catch (RtMidiError &error)
643 {
644 mMidiIn = nullptr;
645 error.printMessage();
646 return false;
647 }
648
649 try
650 {
651 mMidiOut = std::make_unique<RtMidiOut>();
652 }
653 catch (RtMidiError &error)
654 {
655 mMidiOut = nullptr;
656 error.printMessage();
657 return false;
658 }
659
660 mMidiIn->setCallback(&MIDICallback, this);
661 mMidiIn->ignoreTypes(false, true, false );
662
663 return true;
664}
665
666void ApplyFades(double *pBuffer, int nChans, int nFrames, bool down)
667{
668 for (int i = 0; i < nChans; i++)
669 {
670 double *pIO = pBuffer + (i * nFrames);
671
672 if (down)
673 {
674 for (int j = 0; j < nFrames; j++)
675 pIO[j] *= ((double) (nFrames - (j + 1)) / (double) nFrames);
676 }
677 else
678 {
679 for (int j = 0; j < nFrames; j++)
680 pIO[j] *= ((double) j / (double) nFrames);
681 }
682 }
683}
684
685// static
686int IPlugAPPHost::AudioCallback(void* pOutputBuffer, void* pInputBuffer, uint32_t nFrames, double streamTime, RtAudioStreamStatus status, void* pUserData)
687{
688 IPlugAPPHost* _this = (IPlugAPPHost*) pUserData;
689
690 int nins = _this->GetPlug()->MaxNChannels(ERoute::kInput);
691 int nouts = _this->GetPlug()->MaxNChannels(ERoute::kOutput);
692
693 double* pInputBufferD = static_cast<double*>(pInputBuffer);
694 double* pOutputBufferD = static_cast<double*>(pOutputBuffer);
695
696 bool startWait = _this->mVecWait >= APP_N_VECTOR_WAIT; // wait APP_N_VECTOR_WAIT * iovs before processing audio, to avoid clicks
697 bool doFade = _this->mVecWait == APP_N_VECTOR_WAIT || _this->mAudioEnding;
698
699 if (startWait && !_this->mAudioDone)
700 {
701 if (doFade)
702 ApplyFades(pInputBufferD, nins, nFrames, _this->mAudioEnding);
703
704 for (int i = 0; i < nFrames; i++)
705 {
706 _this->mBufIndex %= APP_SIGNAL_VECTOR_SIZE;
707
708 if (_this->mBufIndex == 0)
709 {
710 for (int c = 0; c < nins; c++)
711 {
712 _this->mInputBufPtrs.Set(c, (pInputBufferD + (c * nFrames)) + i);
713 }
714
715 for (int c = 0; c < nouts; c++)
716 {
717 _this->mOutputBufPtrs.Set(c, (pOutputBufferD + (c * nFrames)) + i);
718 }
719
720 _this->mIPlug->AppProcess(_this->mInputBufPtrs.GetList(), _this->mOutputBufPtrs.GetList(), APP_SIGNAL_VECTOR_SIZE);
721
722 _this->mSamplesElapsed += APP_SIGNAL_VECTOR_SIZE;
723 }
724
725 for (int c = 0; c < nouts; c++)
726 {
727 pOutputBufferD[c * nFrames + i] *= APP_MULT;
728 }
729
730 _this->mBufIndex++;
731 }
732
733 if (doFade)
734 ApplyFades(pOutputBufferD, nouts, nFrames, _this->mAudioEnding);
735
736 if (_this->mAudioEnding)
737 _this->mAudioDone = true;
738 }
739 else
740 {
741 memset(pOutputBufferD, 0, nFrames * nouts * sizeof(double));
742 }
743
744 _this->mVecWait = std::min(_this->mVecWait + 1, uint32_t(APP_N_VECTOR_WAIT + 1));
745
746 return 0;
747}
748
749// static
750void IPlugAPPHost::MIDICallback(double deltatime, std::vector<uint8_t>* pMsg, void* pUserData)
751{
752 IPlugAPPHost* _this = (IPlugAPPHost*) pUserData;
753
754 if (pMsg->size() == 0 || _this->mExiting)
755 return;
756
757 if (pMsg->size() > 3)
758 {
759 if(pMsg->size() > MAX_SYSEX_SIZE)
760 {
761 DBGMSG("SysEx message exceeds MAX_SYSEX_SIZE\n");
762 return;
763 }
764
765 SysExData data { 0, static_cast<int>(pMsg->size()), pMsg->data() };
766
767 _this->mIPlug->mSysExMsgsFromCallback.Push(data);
768 return;
769 }
770 else if (pMsg->size())
771 {
772 IMidiMsg msg;
773 msg.mStatus = pMsg->at(0);
774 pMsg->size() > 1 ? msg.mData1 = pMsg->at(1) : msg.mData1 = 0;
775 pMsg->size() > 2 ? msg.mData2 = pMsg->at(2) : msg.mData2 = 0;
776
777 _this->mIPlug->mMidiMsgsFromCallback.Push(msg);
778 }
779}
780
781// static
782void IPlugAPPHost::ErrorCallback(RtAudioError::Type type, const std::string &errorText )
783{
784 //TODO:
785}
786
IPlug logging a.k.a tracing functionality.
A class that hosts an IPlug as a standalone app and provides Audio/Midi I/O.
Definition: IPlugAPP_host.h:82
void ProbeAudioIO()
find out which devices have input channels & which have output channels, add their ids to the lists
int GetMIDIPortNumber(ERoute direction, const char *name) const
int GetAudioDeviceIdx(const char *name) const
Returns the audio device index linked to a particular name.
std::string GetAudioDeviceName(int idx) const
Returns the name of the audio device at idx.
int MaxNChannels(ERoute direction) const
ERoute
Used to identify whether a bus/channel connection is an input or an output.
Encapsulates a MIDI message and provides helper functions.
Definition: IPlugMidi.h:31
This structure is used when queueing Sysex messages.
Definition: IPlugStructs.h:45