diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 76f711d..72398ee 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -40,15 +40,10 @@ libreMediaServerAudio::libreMediaServerAudio() m_updateUi[i][3] = -1; #endif } - if (!m_mae.startEngine(m_layersQty)) { + if (!m_mae.startEngine(m_layersQty, m_settings->getAudioDeviceId(), m_settings->getAudioDeviceQty())) { cout << "Can not start Audio Engine!" << endl; exit(-1); } - uint *audioDevList = m_settings->getAudioDeviceId(); - if (!m_mae.startDevice(audioDevList, m_settings->getAudioDeviceQty())) { - cout << "Can not start Audio Device!" << audioDevList << endl; - exit(-1); - } m_ola = new olaThread(this, m_layersQty); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); diff --git a/src/ma_writer_node.c b/src/ma_writer_node.c index f58881d..82e057c 100644 --- a/src/ma_writer_node.c +++ b/src/ma_writer_node.c @@ -28,7 +28,6 @@ static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFr ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn); } } - //*pFrameCountOut = 0; ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); } diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 33c7840..9b2f64a 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -4,10 +4,6 @@ #define BIAS 0.99f #define FILTER_ORDER 3 -static ma_pcm_rb aux1Buffer; -static ma_data_source_node g_dataSupplyNode; -static ma_data_source_rb g_dataSourceRB; - MiniAudioEngine::MiniAudioEngine() {} void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) @@ -21,83 +17,78 @@ void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const (void)pInput; } -void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) -{ - (void)pDevice; - ma_result result; - - ma_uint32 pcmFramesAvailableInRB = 0; - ma_uint32 pcmFramesProcessed = 0; - while (pcmFramesProcessed < frameCount) { - pcmFramesAvailableInRB = ma_pcm_rb_available_read(&aux1Buffer); - if (pcmFramesAvailableInRB == 0) { - break; - } - ma_uint32 framesToRead = frameCount - pcmFramesProcessed; - if (framesToRead > pcmFramesAvailableInRB) { - framesToRead = pcmFramesAvailableInRB; - } - void* pReadBuffer = NULL; - ma_pcm_rb_acquire_read(&aux1Buffer, &framesToRead, &pReadBuffer); - if (pReadBuffer != NULL) { - ma_copy_pcm_frames(pOutput, pReadBuffer, framesToRead, FORMAT, CHANNELS); - ma_pcm_rb_commit_read(&aux1Buffer, framesToRead); - pcmFramesProcessed += framesToRead; - }/* else { break; }*/ - } - (void)pInput; -} - void MiniAudioEngine::stopEngine() { - for (uint i = 0; i < m_layersQty; i++) { - ma_sound_uninit(&m_currentSound[i]); + for (uint i = 0; i < m_mae.layersQty; i++) { + if (m_mae.mediaLoaded[i]) + ma_sound_uninit(&m_mae.sounds[i]); } - for (uint i = 0; i < m_devicesSelected; i++) { - for (uint j = 0; j < m_layersQty; j++) { - ma_node_uninit(&m_filterBank[i][j].input, NULL); - ma_hpf_node_uninit(&m_filterBank[i][j].hpf, NULL); - ma_loshelf_node_uninit(&m_filterBank[i][j].loshelf, NULL); - ma_peak_node_uninit(&m_filterBank[i][j].mLow, NULL); - ma_peak_node_uninit(&m_filterBank[i][j].mHigh, NULL); - ma_hishelf_node_uninit(&m_filterBank[i][j].hishelf, NULL); - ma_splitter_node_uninit(&m_filterBank[i][j].output, NULL); + for (uint i = 0; i < m_mae.layersQty; i++) { + ma_node_uninit(&m_mae.filters[i].input, NULL); + ma_hpf_node_uninit(&m_mae.filters[i].hpf, NULL); + ma_loshelf_node_uninit(&m_mae.filters[i].loshelf, NULL); + ma_peak_node_uninit(&m_mae.filters[i].mLow, NULL); + ma_peak_node_uninit(&m_mae.filters[i].mHigh, NULL); + ma_hishelf_node_uninit(&m_mae.filters[i].hishelf, NULL); + ma_splitter_node_uninit(&m_mae.filters[i].output, NULL); + } + for (uint i = 0; i < m_mae.audioDevicesQty; i++) { + if (i > 0) { + ma_writer_node_uninit(&m_mae.sendAuxNode[i], NULL); + ma_pcm_rb_uninit(&m_mae.auxBuffers[i]); } - //ma_writer_node_uninit(&m_sendToAux[0], NULL); - //ma_pcm_rb_uninit(&aux1Buffer); - ma_engine_uninit(&m_engine[i]); - ma_device_uninit(&m_device[i]); + ma_engine_uninit(&m_mae.engines[i]); + ma_device_uninit(&m_mae.devices[i]); } - ma_context_uninit(&m_context); - ma_resource_manager_uninit(&m_resourceManager); + ma_context_uninit(&m_mae.context); + ma_resource_manager_uninit(&m_mae.resourceManager); } -bool MiniAudioEngine::startEngine(uint layers) +bool MiniAudioEngine::startEngine(uint layers, uint* audioDevicesId, uint audioDevicesQty) { ma_result result; - m_layersQty = layers; - for (uint i =0; i < m_layersQty; i++) { - m_mediaLoaded[i] = false; - m_currentLayerValues[i].status = Status::Iddle; - m_currentLayerValues[i].pan = 128; - m_currentLayerValues[i].pitch = 128; - m_currentLayerValues[i].vol = 0; - m_currentLayerValues[i].cursor = 0; + m_mae.layersQty = layers; + m_mae.audioDevicesId = audioDevicesId; + m_mae.audioDevicesQty = audioDevicesQty; + for (uint i =0; i < m_mae.layersQty; i++) { + m_mae.mediaLoaded[i] = false; + m_mae.currentStatus[i].status = Status::Iddle; + m_mae.currentStatus[i].pan = 128; + m_mae.currentStatus[i].pitch = 128; + m_mae.currentStatus[i].vol = 0; + m_mae.currentStatus[i].cursor = 0; } result = this->startContext(); if (result != MA_SUCCESS) return false; result = this->getAllAudioDevices(); if (result != MA_SUCCESS) return false; + result = this->startDevices(); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed start audio devices." << endl; + return false; + } + result = this->setNodeGraph(); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to set node graph." << endl; + return false; + } + for (uint i = 0; i < m_mae.audioDevicesQty; i++) { + result = ma_engine_start(&m_mae.engines[i]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to start audio device" << m_mae.audioDevicesId[i] << endl; + return false; + } + } return true; } -ma_result MiniAudioEngine::createFilterBank(int id, uint layer) +ma_result MiniAudioEngine::createFilterBank(uint layer) { ma_result result; - ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); - filterBank *fb = &m_filterBank[id][layer]; + ma_node_graph *ng = ma_engine_get_node_graph(&m_mae.engines[0]); + ma_node *endpoint = ma_engine_get_endpoint(&m_mae.engines[0]); + filterBank *fb = &m_mae.filters[layer]; ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input); @@ -140,13 +131,12 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl; return result; } - + splitterConfig.outputBusCount = m_mae.audioDevicesQty; result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to init output node." << endl; return result; } - result = ma_node_attach_output_bus(&fb->input, 0, &fb->hpf, 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach input node." << endl; @@ -183,137 +173,143 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; return result; } -if (id == 0) { - result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0); + if (m_mae.audioDevicesQty == 1) { + result = ma_node_attach_output_bus(&fb->output, 0, endpoint, 0); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach output node to engine." << endl; + cout << "ERROR " << result << ": Failed to attach output to endpoint." << endl; return result; } - result = ma_node_attach_output_bus(&fb->output, 1, &m_sendToAux[id], 1); + } else { + result = ma_node_attach_output_bus(&fb->output, 0, &m_mae.sendAuxNode[1], 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; return result; } + result = ma_node_attach_output_bus(&fb->output, 1, &m_mae.sendAuxNode[1], 1); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; + return result; + } + for (uint i = 2; i < m_mae.audioDevicesQty; i++) { + result = ma_node_attach_output_bus(&fb->output, i, &m_mae.sendAuxNode[i], 1); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; + return result; + } + } } return result; } -ma_result MiniAudioEngine::setNodeGraph(int id) { +ma_result MiniAudioEngine::setNodeGraph() { ma_result result = MA_SUCCESS; - uint i = 0; - if (id == 0) { - ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - size_t sizeInFrames = SAMPLE_RATE; // ma_get_bytes_per_frame(FORMAT, CHANNELS); - result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &aux1Buffer); - if (result != MA_SUCCESS) { - printf("Failed to initialize ring buffer.\n"); - return result; - } - ma_silence_pcm_frames(aux1Buffer.rb.pBuffer, sizeInFrames, FORMAT, CHANNELS); - ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &aux1Buffer); - result = ma_writer_node_init(ng, &writerConfig, NULL, &m_sendToAux[id]); - if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to init writer node." << endl; - return result; - } - result = ma_node_attach_output_bus(&m_sendToAux[id], 0, ma_engine_get_endpoint(&m_engine[id]), 0); // Pull API - if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach writer node." << endl; - return result; - } + ma_node_graph *ng = ma_engine_get_node_graph(&m_mae.engines[0]); + for (uint i = 1; i < m_mae.audioDevicesQty; i++) { + size_t sizeInFrames = SAMPLE_RATE; + result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &m_mae.auxBuffers[i]); + if (result != MA_SUCCESS) { + printf("Failed to initialize ring buffer.\n"); + return result; + } + ma_silence_pcm_frames(m_mae.auxBuffers[i].rb.pBuffer, sizeInFrames, FORMAT, CHANNELS); + ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &m_mae.auxBuffers[i]); + result = ma_writer_node_init(ng, &writerConfig, NULL, &m_mae.sendAuxNode[i]); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to init writer node." << endl; + return result; + } + // esto va a dar problemas al sumar en el envío 0 una vez por cad envío extra. + // writer_node puede ser silencioso + // así ya estamos en el caso de disparar varios bang por cada envío en el mismo nodegraph + // es mejor que writer node tenga varias entradas, una por cada envío + // que se dispara con un único engine y proporciona un único stream de audio de vuelta a ese engine + // en vez de un puntero hay que pasarle un array de rb + result = ma_node_attach_output_bus(&m_mae.sendAuxNode[i], 0, ma_engine_get_endpoint(&m_mae.engines[0]), 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach writer node." << endl; + return result; + } + result = ma_data_source_rb_init(&m_mae.dataSourceRB[i], &m_mae.auxBuffers[i]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to init data source ring buffer" << endl; + return result; + } + ma_data_source_node_config dataSupplyNodeConfig = ma_data_source_node_config_init(&m_mae.dataSourceRB[i]); + result = ma_data_source_node_init(ma_engine_get_node_graph(&m_mae.engines[i]), &dataSupplyNodeConfig, NULL, &m_mae.dataSupplyNode[i]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to init data source node" << endl; + return result; + } + result = ma_node_attach_output_bus(&m_mae.dataSupplyNode[i], 0, ma_engine_get_endpoint(&m_mae.engines[i]), 0); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to attach data source rb node" << endl; + return result; + } } - while (result == MA_SUCCESS && i < m_layersQty) { - result = this->createFilterBank(id, i); - i++; + for (uint i = 0; i < m_mae.layersQty; i++) { + result = this->createFilterBank(i); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed creating filter bank." << endl; + } } return (result); } -bool MiniAudioEngine::startDevice(uint *systemId, uint nb) +ma_result MiniAudioEngine::startDevices() { ma_result result = MA_SUCCESS; ma_device_config deviceConfig; ma_engine_config engineConfig; - m_devicesSelected = nb; - for (uint internalId = 0; internalId < nb; internalId++) { - deviceConfig = ma_device_config_init(ma_device_type_duplex); - deviceConfig.capture.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; - deviceConfig.capture.format = m_resourceManager.config.decodedFormat; - deviceConfig.capture.channels = CHANNELS; - deviceConfig.capture.shareMode = ma_share_mode_shared; - deviceConfig.playback.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; - deviceConfig.playback.format = m_resourceManager.config.decodedFormat; - deviceConfig.playback.channels = CHANNELS; - deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate; - if (internalId == 0) - deviceConfig.dataCallback = audioDataCallback; - else if (internalId == 1) - deviceConfig.dataCallback = audioDataCallback1; - deviceConfig.pUserData = &m_engine[internalId]; - result = ma_device_init(&m_context, &deviceConfig, &m_device[internalId]); + deviceConfig = ma_device_config_init(ma_device_type_duplex); + deviceConfig.capture.format = m_mae.resourceManager.config.decodedFormat; + deviceConfig.capture.channels = CHANNELS; + deviceConfig.playback.channels = CHANNELS; + deviceConfig.capture.shareMode = ma_share_mode_shared; + deviceConfig.playback.format = m_mae.resourceManager.config.decodedFormat; + deviceConfig.sampleRate = m_mae.resourceManager.config.decodedSampleRate; + deviceConfig.dataCallback = audioDataCallback; + engineConfig = ma_engine_config_init(); + engineConfig.pResourceManager = &m_mae.resourceManager; + engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 25; + engineConfig.noAutoStart = MA_TRUE; + + for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) { + deviceConfig.capture.pDeviceID = &m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].id; + deviceConfig.playback.pDeviceID = &m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].id; + deviceConfig.pUserData = &m_mae.engines[internalId]; + result = ma_device_init(&m_mae.context, &deviceConfig, &m_mae.devices[internalId]); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to initialize audio device " << m_pPlaybackDeviceInfos[*systemId].name << endl; - return false; + cout << "Error " << result << ": Failed to initialize audio device " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; + return result; } - engineConfig = ma_engine_config_init(); - engineConfig.pDevice = &m_device[internalId]; - engineConfig.pResourceManager = &m_resourceManager; - engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 100; - engineConfig.noAutoStart = MA_TRUE; - result = ma_engine_init(&engineConfig, &m_engine[internalId]); + engineConfig.pDevice = &m_mae.devices[internalId]; + result = ma_engine_init(&engineConfig, &m_mae.engines[internalId]); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to initialize audio engine" << endl; - return false; + return result; } - result = this->setNodeGraph(internalId); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to set node graph " << systemId[internalId] << endl; - return false; - } - result = ma_engine_start(&m_engine[internalId]); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to start audio engine" << systemId[internalId] << endl; - return false; - } - cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << systemId[internalId] << " " << m_pPlaybackDeviceInfos[systemId[internalId]].name << endl; + cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << m_mae.audioDevicesId[internalId] << " " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; } - //result = ma_data_source_rb_init(&g_dataSourceRB, &aux1Buffer); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to init data source ring buffer" << endl; - return false; - } - ma_data_source_node_config dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSourceRB); - //result = ma_data_source_node_init(ma_engine_get_node_graph(&m_engine[1]), &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to init data source node" << endl; - return false; - } - //result = ma_node_attach_output_bus(&g_dataSupplyNode, 0, ma_engine_get_endpoint(&m_engine[1]), 0); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to attach data source rb node" << endl; - return false; - } - cout << "data source node state " << ma_node_get_state(&g_dataSupplyNode.base) << endl; - return true; + return result; } ma_result MiniAudioEngine::startContext() { ma_result result; - m_resourceManagerConfig = ma_resource_manager_config_init(); - m_resourceManagerConfig.decodedFormat = FORMAT; - m_resourceManagerConfig.decodedChannels = CHANNELS; - m_resourceManagerConfig.decodedSampleRate = SAMPLE_RATE; - m_resourceManagerConfig.jobThreadCount = 4; - result = ma_resource_manager_init(&m_resourceManagerConfig, &m_resourceManager); + ma_resource_manager_config resourceManagerConfig = ma_resource_manager_config_init(); + resourceManagerConfig.decodedFormat = FORMAT; + resourceManagerConfig.decodedChannels = CHANNELS; + resourceManagerConfig.decodedSampleRate = SAMPLE_RATE; + resourceManagerConfig.jobThreadCount = MAX_LAYERS; + result = ma_resource_manager_init(&resourceManagerConfig, &m_mae.resourceManager); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to initialize audio resource manager." << endl; return result; } - result = ma_context_init(NULL, 0, NULL, &m_context); + result = ma_context_init(NULL, 0, NULL, &m_mae.context); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to initialize audio context." << endl; } @@ -325,15 +321,15 @@ ma_result MiniAudioEngine::getAllAudioDevices() { ma_result result; - result = ma_context_get_devices(&m_context, &m_pPlaybackDeviceInfos, &m_playbackDeviceCount, NULL, NULL); + result = ma_context_get_devices(&m_mae.context, &m_mae.pPlaybackDeviceInfos, &m_mae.playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to enumerate playback devices." << endl; - ma_context_uninit(&m_context); + ma_context_uninit(&m_mae.context); return result; } cout << "Audio devices available:" << endl; - for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_playbackDeviceCount; iAvailableDevice += 1) { - cout << iAvailableDevice << " : " << m_pPlaybackDeviceInfos[iAvailableDevice].name << endl; + for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_mae.playbackDeviceCount; iAvailableDevice += 1) { + cout << iAvailableDevice << " : " << m_mae.pPlaybackDeviceInfos[iAvailableDevice].name << endl; } return result; } @@ -342,28 +338,26 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) { ma_result result; - // - iniciar un sonido por cada capa, copiar la capa en otro dispositivo - // - writer node y source con el buffer escrito en el otro device - if (m_mediaLoaded[layer] == true) + if (m_mae.mediaLoaded[layer] == true) { - ma_sound_uninit(&m_currentSound[layer]); - m_mediaLoaded[layer] = false; + ma_sound_uninit(&m_mae.sounds[layer]); + m_mae.mediaLoaded[layer] = false; } - result = ma_sound_init_from_file(&m_engine[audioDevice], file, \ + result = ma_sound_init_from_file(&m_mae.engines[0], file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ - , NULL, NULL, &m_currentSound[layer]); + , NULL, NULL, &m_mae.sounds[layer]); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to load file " << file << endl; return result; } - result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].input, 0); + result = ma_node_attach_output_bus(&m_mae.sounds[layer], 0, &m_mae.filters[layer].input, 0); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl; - //return result; + return result; } - m_mediaLoaded[layer] = true; + m_mae.mediaLoaded[layer] = true; this->refreshValues(layer); - m_currentLayerValues[layer].media = file; + m_mae.currentStatus[layer].media = file; return result; } @@ -372,9 +366,9 @@ float MiniAudioEngine::getDuration(int layer) ma_result result; float ret; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret); + result = ma_sound_get_length_in_seconds(&m_mae.sounds[layer], &ret); if (result != MA_SUCCESS) { return result; } @@ -386,9 +380,9 @@ float MiniAudioEngine::getCursor(int layer) ma_result result; float ret = 0; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret); + result = ma_sound_get_cursor_in_seconds(&m_mae.sounds[layer], &ret); if (result != MA_SUCCESS) { cout << "Error" << result << ": Can not get cursor " << layer << endl; @@ -403,16 +397,16 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) ma_uint32 channels; ma_uint32 sampleRate; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - ma_result result = ma_sound_get_data_format(&m_currentSound[layer], \ + ma_result result = ma_sound_get_data_format(&m_mae.sounds[layer], \ &format, &channels, &sampleRate, NULL, 0); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to get data format " << layer; cout << endl; } else { cout << "Layer:" << layer << " "; - cout << m_currentLayerValues[layer].media.toLatin1().data(); + cout << m_mae.currentStatus[layer].media.toLatin1().data(); cout << " samples/sec:" << sampleRate << " format:" << format; cout << " channels:" << channels << endl; } @@ -422,50 +416,50 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) // Expects between 0 and 1 vol value void MiniAudioEngine::volChanged(int layer, float vol) { - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return; if (vol >= 1) vol = 0.99f; - ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, pow(vol, 3), FADE_TIME); - m_currentLayerValues[layer].vol = vol; + ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, pow(vol, 3), FADE_TIME); + m_mae.currentStatus[layer].vol = vol; } void MiniAudioEngine::panChanged(int layer, float value) { float result; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return; result = (value / 128.0) - 1.0; - ma_sound_group_set_pan(&m_currentSound[layer], result); - m_currentLayerValues[layer].pan = value; + ma_sound_group_set_pan(&m_mae.sounds[layer], result); + m_mae.currentStatus[layer].pan = value; } void MiniAudioEngine::pitchChanged(int layer, float value) { float pitch; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return; pitch = value / 128.0; - ma_sound_group_set_pitch(&m_currentSound[layer], pitch); - m_currentLayerValues[layer].pitch = value; + ma_sound_group_set_pitch(&m_mae.sounds[layer], pitch); + m_mae.currentStatus[layer].pitch = value; } ma_result MiniAudioEngine::playbackChanged(int layer, Status status) { ma_result result = MA_SUCCESS; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; bool loop = false; switch (status) { case Status::Paused: - result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); + result = ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); break; case Status::Stopped: - ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); - result = this->seekToCursor(layer, m_currentLayerValues[layer].cursor); + ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); + result = this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); break; case Status::PlayingLoop: loop = true; @@ -473,18 +467,18 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) case Status::PlayingFolder: case Status::PlayingFolderLoop: case Status::PlayingFolderRandom: - ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0); - ma_sound_set_looping(&m_currentSound[layer], loop); - result = ma_sound_start(&m_currentSound[layer]); - if (m_currentLayerValues[layer].cursor != 0) { + ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0); + ma_sound_set_looping(&m_mae.sounds[layer], loop); + result = ma_sound_start(&m_mae.sounds[layer]); + if (m_mae.currentStatus[layer].cursor != 0) { usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line? } - this->volChanged(layer, m_currentLayerValues[layer].vol); + this->volChanged(layer, m_mae.currentStatus[layer].vol); default: break; } if (result == MA_SUCCESS) - m_currentLayerValues[layer].status = status; + m_mae.currentStatus[layer].status = status; return result; } @@ -493,13 +487,13 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) ma_result result = MA_SUCCESS; ma_uint64 end, start; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end); + result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); if (result != MA_SUCCESS) { return result; } start = (cursor * end) / 65025; - result = ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start); - //result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end); // this do nothing here, it must be done after set_looping or start? + result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], start); + //result = ma_data_source_set_loop_point_in_pcm_frames(&m_mae.sounds[layer], start, end); // this do nothing here, it must be done after set_looping or start? return (result); } @@ -507,30 +501,30 @@ ma_result MiniAudioEngine::setCursor(int layer, int cursor) { ma_result result = MA_SUCCESS; - m_currentLayerValues[layer].cursor = cursor; + m_mae.currentStatus[layer].cursor = cursor; result = this->seekToCursor(layer, cursor); return (result); } Status MiniAudioEngine::getStatus(int layer) { - return m_currentLayerValues[layer].status; + return m_mae.currentStatus[layer].status; } void MiniAudioEngine::refreshValues(int layer) { - this->seekToCursor(layer, m_currentLayerValues[layer].cursor); - this->panChanged(layer, m_currentLayerValues[layer].pan); - this->volChanged(layer, m_currentLayerValues[layer].vol); - this->pitchChanged(layer, m_currentLayerValues[layer].pitch); - this->playbackChanged(layer, m_currentLayerValues[layer].status); + this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); + this->panChanged(layer, m_mae.currentStatus[layer].pan); + this->volChanged(layer, m_mae.currentStatus[layer].vol); + this->pitchChanged(layer, m_mae.currentStatus[layer].pitch); + this->playbackChanged(layer, m_mae.currentStatus[layer].status); } ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int channel, int value) { + (void)audioDevice; ma_result result = MA_SUCCESS; - - filterBank *fb = &m_filterBank[audioDevice][layer]; + filterBank *fb = &m_mae.filters[layer]; if (channel == HP_FREQ) { fb->hpfConfig.hpf.cutoffFrequency = double((value * 1.31) + 16.0f); // 16 - 350 @@ -641,7 +635,8 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) { - filterBank *fb = &m_filterBank[audioDevice][layer]; + (void)audioDevice; + filterBank *fb = &m_mae.filters[layer]; if (bypass) { ma_node_set_output_bus_volume(&fb->input, 1, 1.0f); diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 69147d3..308706b 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -15,7 +15,6 @@ using namespace std; #include "defines.h" - typedef struct { ma_splitter_node input; @@ -30,32 +29,40 @@ typedef struct ma_hishelf_node hishelf; ma_hishelf_node_config hishelfConfig; ma_splitter_node output; - ma_writer_node send1; - ma_data_source_node return1; - ma_audio_buffer_ref supplyReturn1; } filterBank; typedef struct { - ma_engine m_engine[MAX_AUDIODEVICES]; - filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS]; - ma_writer_node m_sendAux1[MAX_LAYERS]; - ma_pcm_rb *aux1Buffer; -} audioObjects; + ma_engine engines[MAX_AUDIODEVICES]; + ma_device devices[MAX_AUDIODEVICES]; + filterBank filters[MAX_LAYERS]; + ma_writer_node sendAuxNode[MAX_AUDIODEVICES]; + ma_pcm_rb auxBuffers[MAX_AUDIODEVICES]; + ma_node_graph ng; + layerData currentStatus[MAX_LAYERS]; + ma_sound sounds[MAX_LAYERS]; + ma_resource_manager resourceManager; + ma_context context; + ma_device_info* pPlaybackDeviceInfos; + ma_uint32 playbackDeviceCount; + ma_uint32 devicesSelected; + ma_bool8 mediaLoaded[MAX_LAYERS]; + uint layersQty; + uint *audioDevicesId; + uint audioDevicesQty; + ma_data_source_node dataSupplyNode[MAX_AUDIODEVICES]; + ma_data_source_rb dataSourceRB[MAX_AUDIODEVICES]; +} MAE; class MiniAudioEngine { friend class libreMediaServerAudio; - static ma_pcm_rb *rb; public: MiniAudioEngine(); void stopEngine(); - bool startEngine(uint layersQty); - bool startDevice(uint *id, uint nb); + bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - static void audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - bool setBypass(int audioDevice, int layer, bool bypass); protected: ma_result loadMedia(int layer, char *media, uint audioDevice); @@ -69,33 +76,21 @@ protected: float getCursor(int layer); Status getStatus(int layer); inline float getVol(int layer) { - return ma_sound_get_volume(&m_currentSound[layer]); } - inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; } + return ma_sound_get_volume(&m_mae.sounds[layer]); } + inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; } ma_result filterParamChanged(int layer, int audioDevice, int channel, int value); + bool setBypass(int audioDevice, int layer, bool bypass); private: - ma_resource_manager_config m_resourceManagerConfig; - ma_resource_manager m_resourceManager; - ma_context m_context; - ma_device_info* m_pPlaybackDeviceInfos; - ma_uint32 m_playbackDeviceCount; - ma_uint32 m_devicesSelected; - ma_device m_device[MAX_AUDIODEVICES]; - ma_sound m_currentSound[MAX_LAYERS]; - ma_bool8 m_mediaLoaded[MAX_LAYERS]; - layerData m_currentLayerValues[MAX_LAYERS]; - filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS]; - ma_engine m_engine[MAX_AUDIODEVICES]; - uint m_layersQty; - ma_writer_node m_sendToAux[MAX_LAYERS]; - audioObjects m_audioObjects; + MAE m_mae; + ma_result startDevices(); ma_result getAllAudioDevices(); ma_result startContext(); void refreshValues(int layer); ma_result seekToCursor(int layer, int cursor); - ma_result setNodeGraph(int id); - ma_result createFilterBank(int id, uint layer); + ma_result setNodeGraph(); + ma_result createFilterBank(uint layer); }; #endif // MINIAUDIOENGINE_H