2#include <ossia/detail/config.hpp>
4#if defined(OSSIA_ENABLE_ASIO)
5#include <ossia/audio/audio_engine.hpp>
6#include <ossia/detail/thread.hpp>
8#if !defined(WIN32_LEAN_AND_MEAN)
9#define WIN32_LEAN_AND_MEAN
16#include <asiodrivers.h>
20bool loadAsioDriver(
char *name);
21extern AsioDrivers* asioDrivers;
30#define OSSIA_AUDIO_ASIO 1
46inline asio_engine* current_asio_engine =
nullptr;
49class asio_engine final :
public audio_engine
53 std::string driver_name,
int inputs,
int outputs,
int rate,
int bs)
55 if(detail::current_asio_engine)
56 throw std::runtime_error(
"ASIO error: only one ASIO engine can be active at a time");
58 detail::current_asio_engine =
this;
61 if(!loadAsioDriver(
const_cast<char*
>(driver_name.c_str())))
63 detail::current_asio_engine =
nullptr;
64 throw std::runtime_error(
"ASIO error: could not load driver '" + driver_name +
"'");
68 ASIODriverInfo driverInfo{};
69 driverInfo.asioVersion = 2;
70 driverInfo.sysRef =
nullptr;
72 if(ASIOInit(&driverInfo) != ASE_OK)
75 throw std::runtime_error(
76 std::string(
"ASIO error: ASIOInit failed: ") + driverInfo.errorMessage);
81 long maxInputChannels = 0, maxOutputChannels = 0;
82 if(ASIOGetChannels(&maxInputChannels, &maxOutputChannels) != ASE_OK)
85 throw std::runtime_error(
"ASIO error: ASIOGetChannels failed");
88 inputs = std::min((
long)inputs, maxInputChannels);
89 outputs = std::min((
long)outputs, maxOutputChannels);
91 if(inputs == 0 && outputs == 0)
94 throw std::runtime_error(
"ASIO error: no channels available");
98 if(ASIOCanSampleRate((ASIOSampleRate)rate) != ASE_OK)
101 ASIOSampleRate currentRate = 0;
102 if(ASIOGetSampleRate(¤tRate) == ASE_OK && currentRate > 0)
104 rate = (int)currentRate;
109 throw std::runtime_error(
"ASIO error: sample rate not supported");
114 if(ASIOSetSampleRate((ASIOSampleRate)rate) != ASE_OK)
117 throw std::runtime_error(
"ASIO error: could not set sample rate");
122 long minSize = 0, maxSize = 0, preferredSize = 0, granularity = 0;
123 if(ASIOGetBufferSize(&minSize, &maxSize, &preferredSize, &granularity) != ASE_OK)
126 throw std::runtime_error(
"ASIO error: ASIOGetBufferSize failed");
132 bs = std::max(bs, (
int)minSize);
133 bs = std::min(bs, (
int)maxSize);
136 if(granularity == -1)
139 while(pot < bs && pot < maxSize)
143 else if(granularity > 0)
145 bs = ((bs + granularity - 1) / granularity) * granularity;
146 bs = std::min(bs, (
int)maxSize);
150 m_inputCount = inputs;
151 m_outputCount = outputs;
154 int totalChannels = inputs + outputs;
155 m_bufferInfos.resize(totalChannels);
156 m_channelInfos.resize(totalChannels);
159 for(
int i = 0; i < inputs; i++, idx++)
161 m_bufferInfos[idx].isInput = ASIOTrue;
162 m_bufferInfos[idx].channelNum = i;
163 m_bufferInfos[idx].buffers[0] = m_bufferInfos[idx].buffers[1] =
nullptr;
165 for(
int i = 0; i < outputs; i++, idx++)
167 m_bufferInfos[idx].isInput = ASIOFalse;
168 m_bufferInfos[idx].channelNum = i;
169 m_bufferInfos[idx].buffers[0] = m_bufferInfos[idx].buffers[1] =
nullptr;
173 m_asioCallbacks.bufferSwitch = &asio_bufferSwitch;
174 m_asioCallbacks.sampleRateDidChange = &asio_sampleRateDidChange;
175 m_asioCallbacks.asioMessage = &asio_message;
176 m_asioCallbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo;
179 if(ASIOCreateBuffers(
180 m_bufferInfos.data(), totalChannels, m_bufferSize, &m_asioCallbacks)
184 throw std::runtime_error(
"ASIO error: ASIOCreateBuffers failed");
186 m_buffersCreated =
true;
189 for(
int i = 0; i < totalChannels; i++)
191 m_channelInfos[i].channel = m_bufferInfos[i].channelNum;
192 m_channelInfos[i].isInput = m_bufferInfos[i].isInput;
193 if(ASIOGetChannelInfo(&m_channelInfos[i]) != ASE_OK)
196 throw std::runtime_error(
"ASIO error: ASIOGetChannelInfo failed");
201 m_postOutput = (ASIOOutputReady() == ASE_OK);
204 m_floatInputs.resize(inputs);
205 m_floatOutputs.resize(outputs);
206 m_inputPtrs.resize(inputs);
207 m_outputPtrs.resize(outputs);
208 for(
int i = 0; i < inputs; i++)
210 m_floatInputs[i].resize(m_bufferSize);
211 m_inputPtrs[i] = m_floatInputs[i].data();
213 for(
int i = 0; i < outputs; i++)
215 m_floatOutputs[i].resize(m_bufferSize);
216 m_outputPtrs[i] = m_floatOutputs[i].data();
220 this->effective_sample_rate = rate;
221 this->effective_buffer_size = m_bufferSize;
222 this->effective_inputs = inputs;
223 this->effective_outputs = outputs;
226 if(ASIOStart() != ASE_OK)
229 throw std::runtime_error(
"ASIO error: ASIOStart failed");
234 bool running()
const override {
return m_started && !stop_processing; }
238 audio_engine::stop();
247 ~asio_engine()
override
253 static std::vector<asio_card> enumerate_drivers()
255 std::vector<asio_card> cards;
258 long numDrivers = drivers.asioGetNumDev();
259 for(
long i = 0; i < numDrivers; i++)
262 if(drivers.asioGetDriverName(i, name,
sizeof(name)) == 0)
264 cards.push_back({name, (int)i});
273 static void open_control_panel(
const std::string& driver_name)
276 if(detail::current_asio_engine)
283 if(!loadAsioDriver(
const_cast<char*
>(driver_name.c_str())))
286 ASIODriverInfo info{};
287 info.asioVersion = 2;
288 if(ASIOInit(&info) == ASE_OK)
309 ASIODisposeBuffers();
310 m_buffersCreated =
false;
316 m_initialized =
false;
326 asioDrivers->removeCurrentDriver();
328 detail::current_asio_engine =
nullptr;
332 static void convertToFloat(
333 void* src,
float* dst,
long frames, ASIOSampleType type)
337 case ASIOSTFloat32LSB:
339 std::memcpy(dst, src, frames *
sizeof(
float));
342 case ASIOSTFloat64LSB:
344 auto* s =
static_cast<double*
>(src);
345 for(
long i = 0; i < frames; i++)
346 dst[i] = (
float)s[i];
351 auto* s =
static_cast<int32_t*
>(src);
352 constexpr float scale = 1.0f / 2147483648.0f;
353 for(
long i = 0; i < frames; i++)
354 dst[i] = s[i] * scale;
359 auto* s =
static_cast<uint8_t*
>(src);
360 constexpr float scale = 1.0f / 8388608.0f;
361 for(
long i = 0; i < frames; i++)
363 int32_t val = (int32_t(s[i * 3 + 2]) << 24) | (int32_t(s[i * 3 + 1]) << 16)
364 | (int32_t(s[i * 3]) << 8);
365 dst[i] = (val >> 8) * scale;
371 auto* s =
static_cast<int16_t*
>(src);
372 constexpr float scale = 1.0f / 32768.0f;
373 for(
long i = 0; i < frames; i++)
374 dst[i] = s[i] * scale;
377 case ASIOSTInt32LSB16:
379 auto* s =
static_cast<int32_t*
>(src);
380 constexpr float scale = 1.0f / 32768.0f;
381 for(
long i = 0; i < frames; i++)
382 dst[i] = (s[i] & 0xFFFF) * scale;
385 case ASIOSTInt32LSB18:
387 auto* s =
static_cast<int32_t*
>(src);
388 constexpr float scale = 1.0f / 131072.0f;
389 for(
long i = 0; i < frames; i++)
390 dst[i] = (s[i] & 0x3FFFF) * scale;
393 case ASIOSTInt32LSB20:
395 auto* s =
static_cast<int32_t*
>(src);
396 constexpr float scale = 1.0f / 524288.0f;
397 for(
long i = 0; i < frames; i++)
398 dst[i] = (s[i] & 0xFFFFF) * scale;
401 case ASIOSTInt32LSB24:
403 auto* s =
static_cast<int32_t*
>(src);
404 constexpr float scale = 1.0f / 8388608.0f;
405 for(
long i = 0; i < frames; i++)
406 dst[i] = (s[i] & 0xFFFFFF) * scale;
410 case ASIOSTFloat32MSB:
412 auto* s =
static_cast<uint8_t*
>(src);
413 for(
long i = 0; i < frames; i++)
415 uint32_t val = (uint32_t(s[i * 4]) << 24) | (uint32_t(s[i * 4 + 1]) << 16)
416 | (uint32_t(s[i * 4 + 2]) << 8) | uint32_t(s[i * 4 + 3]);
418 std::memcpy(&f, &val, 4);
425 auto* s =
static_cast<uint8_t*
>(src);
426 constexpr float scale = 1.0f / 2147483648.0f;
427 for(
long i = 0; i < frames; i++)
429 int32_t val = (int32_t(s[i * 4]) << 24) | (int32_t(s[i * 4 + 1]) << 16)
430 | (int32_t(s[i * 4 + 2]) << 8) | int32_t(s[i * 4 + 3]);
431 dst[i] = val * scale;
437 auto* s =
static_cast<uint8_t*
>(src);
438 constexpr float scale = 1.0f / 32768.0f;
439 for(
long i = 0; i < frames; i++)
441 int16_t val = (int16_t(s[i * 2]) << 8) | int16_t(s[i * 2 + 1]);
442 dst[i] = val * scale;
447 std::memset(dst, 0, frames *
sizeof(
float));
453 static void convertFromFloat(
454 const float* src,
void* dst,
long frames, ASIOSampleType type)
458 case ASIOSTFloat32LSB:
460 std::memcpy(dst, src, frames *
sizeof(
float));
463 case ASIOSTFloat64LSB:
465 auto* d =
static_cast<double*
>(dst);
466 for(
long i = 0; i < frames; i++)
467 d[i] = (
double)src[i];
472 auto* d =
static_cast<int32_t*
>(dst);
473 constexpr double scale = 2147483647.0;
474 for(
long i = 0; i < frames; i++)
476 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
477 d[i] = (int32_t)(val * scale);
483 auto* d =
static_cast<uint8_t*
>(dst);
484 constexpr double scale = 8388607.0;
485 for(
long i = 0; i < frames; i++)
487 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
488 int32_t s = (int32_t)(val * scale);
489 d[i * 3] = (uint8_t)(s & 0xFF);
490 d[i * 3 + 1] = (uint8_t)((s >> 8) & 0xFF);
491 d[i * 3 + 2] = (uint8_t)((s >> 16) & 0xFF);
497 auto* d =
static_cast<int16_t*
>(dst);
498 constexpr double scale = 32767.0;
499 for(
long i = 0; i < frames; i++)
501 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
502 d[i] = (int16_t)(val * scale);
506 case ASIOSTInt32LSB16:
508 auto* d =
static_cast<int32_t*
>(dst);
509 constexpr double scale = 32767.0;
510 for(
long i = 0; i < frames; i++)
512 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
513 d[i] = (int32_t)(val * scale);
517 case ASIOSTInt32LSB18:
519 auto* d =
static_cast<int32_t*
>(dst);
520 constexpr double scale = 131071.0;
521 for(
long i = 0; i < frames; i++)
523 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
524 d[i] = (int32_t)(val * scale);
528 case ASIOSTInt32LSB20:
530 auto* d =
static_cast<int32_t*
>(dst);
531 constexpr double scale = 524287.0;
532 for(
long i = 0; i < frames; i++)
534 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
535 d[i] = (int32_t)(val * scale);
539 case ASIOSTInt32LSB24:
541 auto* d =
static_cast<int32_t*
>(dst);
542 constexpr double scale = 8388607.0;
543 for(
long i = 0; i < frames; i++)
545 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
546 d[i] = (int32_t)(val * scale);
550 case ASIOSTFloat32MSB:
552 auto* d =
static_cast<uint8_t*
>(dst);
553 for(
long i = 0; i < frames; i++)
556 std::memcpy(&val, &src[i], 4);
557 d[i * 4] = (uint8_t)(val >> 24);
558 d[i * 4 + 1] = (uint8_t)(val >> 16);
559 d[i * 4 + 2] = (uint8_t)(val >> 8);
560 d[i * 4 + 3] = (uint8_t)(val);
566 auto* d =
static_cast<uint8_t*
>(dst);
567 constexpr double scale = 2147483647.0;
568 for(
long i = 0; i < frames; i++)
570 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
571 int32_t s = (int32_t)(val * scale);
572 d[i * 4] = (uint8_t)(s >> 24);
573 d[i * 4 + 1] = (uint8_t)(s >> 16);
574 d[i * 4 + 2] = (uint8_t)(s >> 8);
575 d[i * 4 + 3] = (uint8_t)(s);
581 auto* d =
static_cast<uint8_t*
>(dst);
582 constexpr double scale = 32767.0;
583 for(
long i = 0; i < frames; i++)
585 double val = std::max(-1.0, std::min(1.0, (
double)src[i]));
586 int16_t s = (int16_t)(val * scale);
587 d[i * 2] = (uint8_t)(s >> 8);
588 d[i * 2 + 1] = (uint8_t)(s);
599 static ASIOTime* asio_bufferSwitchTimeInfo(
600 ASIOTime* params,
long doubleBufferIndex, ASIOBool directProcess)
602 auto* self = detail::current_asio_engine;
606 [[maybe_unused]]
static const thread_local auto _ = [] {
607 ossia::set_thread_name(
"ossia audio 0");
608 ossia::set_thread_pinned(thread_type::Audio, 0);
614 if(self->stop_processing)
618 for(
int i = 0; i < self->m_outputCount; i++)
620 auto& info = self->m_bufferInfos[self->m_inputCount + i];
621 auto& chanInfo = self->m_channelInfos[self->m_inputCount + i];
622 void* buf = info.buffers[doubleBufferIndex];
625 std::memset(buf, 0, self->sampleSize(chanInfo.type) * self->m_bufferSize);
628 if(self->m_postOutput)
633 const long frames = self->m_bufferSize;
636 for(
int i = 0; i < self->m_inputCount; i++)
638 void* src = self->m_bufferInfos[i].buffers[doubleBufferIndex];
639 convertToFloat(src, self->m_inputPtrs[i], frames, self->m_channelInfos[i].type);
643 for(
int i = 0; i < self->m_outputCount; i++)
645 std::memset(self->m_outputPtrs[i], 0, frames *
sizeof(
float));
652 double seconds = 0.0;
653 if(params && (params->timeInfo.flags & kSystemTimeValid))
655 seconds = asioSamplesToDouble(params->timeInfo.systemTime) * 1e-9;
659 ossia::audio_tick_state ts{
660 const_cast<float* const*
>(self->m_inputPtrs.data()),
661 self->m_outputPtrs.data(),
667 self->audio_tick(ts);
671 for(
int i = 0; i < self->m_outputCount; i++)
673 int chIdx = self->m_inputCount + i;
674 void* dst = self->m_bufferInfos[chIdx].buffers[doubleBufferIndex];
676 self->m_outputPtrs[i], dst, frames, self->m_channelInfos[chIdx].type);
679 if(self->m_postOutput)
685 static void asio_bufferSwitch(
long doubleBufferIndex, ASIOBool directProcess)
689 std::memset(&timeInfo, 0,
sizeof(ASIOTime));
692 ASIOTimeStamp tStamp;
693 if(ASIOGetSamplePosition(&sPos, &tStamp) == ASE_OK)
695 timeInfo.timeInfo.samplePosition = sPos;
696 timeInfo.timeInfo.systemTime = tStamp;
697 timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
700 ASIOSampleRate sRate = 0;
701 if(ASIOGetSampleRate(&sRate) == ASE_OK)
703 timeInfo.timeInfo.sampleRate = sRate;
704 timeInfo.timeInfo.flags |= kSampleRateValid;
707 asio_bufferSwitchTimeInfo(&timeInfo, doubleBufferIndex, directProcess);
710 static void asio_sampleRateDidChange(ASIOSampleRate sRate)
712 auto* self = detail::current_asio_engine;
713 if(self && sRate > 0)
715 self->effective_sample_rate = (int)sRate;
719 static long asio_message(
long selector,
long value,
void* message,
double* opt)
723 case kAsioSelectorSupported:
726 case kAsioEngineVersion:
727 case kAsioSupportsTimeInfo:
728 case kAsioResetRequest:
729 case kAsioResyncRequest:
730 case kAsioLatenciesChanged:
737 case kAsioEngineVersion:
740 case kAsioSupportsTimeInfo:
743 case kAsioResetRequest:
747 case kAsioResyncRequest:
750 case kAsioLatenciesChanged:
761 static double asioSamplesToDouble(
const ASIOSamples& s)
766 return s.hi * 4294967296.0 + s.lo;
770 static double asioSamplesToDouble(
const ASIOTimeStamp& s)
775 return s.hi * 4294967296.0 + s.lo;
779 static long sampleSize(ASIOSampleType type)
791 case ASIOSTFloat32MSB:
792 case ASIOSTFloat32LSB:
793 case ASIOSTInt32MSB16:
794 case ASIOSTInt32MSB18:
795 case ASIOSTInt32MSB20:
796 case ASIOSTInt32MSB24:
797 case ASIOSTInt32LSB16:
798 case ASIOSTInt32LSB18:
799 case ASIOSTInt32LSB20:
800 case ASIOSTInt32LSB24:
802 case ASIOSTFloat64MSB:
803 case ASIOSTFloat64LSB:
810 std::vector<ASIOBufferInfo> m_bufferInfos;
811 std::vector<ASIOChannelInfo> m_channelInfos;
812 ASIOCallbacks m_asioCallbacks{};
815 std::vector<std::vector<float>> m_floatInputs;
816 std::vector<std::vector<float>> m_floatOutputs;
817 std::vector<float*> m_inputPtrs;
818 std::vector<float*> m_outputPtrs;
824 bool m_initialized{};
825 bool m_buffersCreated{};