refactorizado todo a una struct.

Maximo de dispositivos MAX_AUDIODEVICES, sin testear mas de dos.
Los devices auxiliares leen de data source rb en vez de en el callback.
la idea del nodegraph funcionando en una engine dummy no ha funcionado,
pero puede que fuera por la refactorización y la introducción de las
data sources rb. Ahora que está todo más ordenado se puede volver a
intentar. Pero tampoco merece mucho la pena, la principal diferencia era
el master bus, pero se puede atacar la salida de auxNode[0] a una capa
de master en vez de al endpoint directamente.
This commit is contained in:
snt 2024-05-20 19:00:05 +02:00
parent a935d4e619
commit 5d56921aeb
4 changed files with 234 additions and 250 deletions

View file

@ -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);

View file

@ -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);
}

View file

@ -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);
}
//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]);
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_context_uninit(&m_context);
ma_resource_manager_uninit(&m_resourceManager);
ma_engine_uninit(&m_mae.engines[i]);
ma_device_uninit(&m_mae.devices[i]);
}
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);
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(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]);
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;
}
result = ma_node_attach_output_bus(&m_sendToAux[id], 0, ma_engine_get_endpoint(&m_engine[id]), 0); // Pull API
// 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;
}
}
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;
}
while (result == MA_SUCCESS && i < m_layersQty) {
result = this->createFilterBank(id, i);
i++;
}
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.format = m_mae.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.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.format = m_mae.resourceManager.config.decodedFormat;
deviceConfig.sampleRate = m_mae.resourceManager.config.decodedSampleRate;
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]);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to initialize audio device " << m_pPlaybackDeviceInfos[*systemId].name << endl;
return false;
}
engineConfig = ma_engine_config_init();
engineConfig.pDevice = &m_device[internalId];
engineConfig.pResourceManager = &m_resourceManager;
engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 100;
engineConfig.pResourceManager = &m_mae.resourceManager;
engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 25;
engineConfig.noAutoStart = MA_TRUE;
result = ma_engine_init(&engineConfig, &m_engine[internalId]);
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_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl;
return result;
}
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;
cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << m_mae.audioDevicesId[internalId] << " " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl;
}
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;
}
//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);

View file

@ -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