Compare commits

..

No commits in common. "200dcf86d45e1d760368ebb9b772975da35cea19" and "a935d4e619144c338bd5ec10f73c82a656776dbc" have entirely different histories.

12 changed files with 295 additions and 346 deletions

View file

@ -46,10 +46,6 @@ v 0.2.1
- Hardening: check return errors, try/catch exceptions, i'm too happy.... - Hardening: check return errors, try/catch exceptions, i'm too happy....
- Tests: errors on wrong conf file. - Tests: errors on wrong conf file.
- Ui/Ux: seek cursor playback - Ui/Ux: seek cursor playback
- ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer
v0.2.0: v0.2.0:
- Vumeter or indicator about audio output in layer and master, add to sliderGroup. - Vumeter or indicator about audio output in layer and master, add to sliderGroup.
--> en master se puede hacer con jack, solo en capas.
--> en las capas, hace falta otro nodo atacado en los buses de input que analice la entrada.
- mostrad información de envíos y dispositivos en ui

View file

@ -1,5 +1,4 @@
#include "audiolayerwidget.h" #include "audiolayerwidget.h"
#include "dmxPersonality.h"
#include <QBoxLayout> #include <QBoxLayout>
#include <QFileDialog> #include <QFileDialog>
@ -12,6 +11,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
{ {
QVBoxLayout *layout = new QVBoxLayout; QVBoxLayout *layout = new QVBoxLayout;
QVBoxLayout *playback = new QVBoxLayout;
m_folderValue = new ClickableLabel; m_folderValue = new ClickableLabel;
m_folderValue->setMaximumWidth(300); m_folderValue->setMaximumWidth(300);
m_folderValue->setAlignment(Qt::AlignLeft); m_folderValue->setAlignment(Qt::AlignLeft);
@ -19,7 +19,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
"color: white;" "color: white;"
"background-color: black;" "background-color: black;"
); );
layout->addWidget(m_folderValue); playback->addWidget(m_folderValue);
m_fileValue = new ClickableLabel; m_fileValue = new ClickableLabel;
connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog()));
connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog()));
@ -29,7 +29,10 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
"color: white;" "color: white;"
"background-color: black;" "background-color: black;"
); );
layout->addWidget(m_fileValue); playback->addWidget(m_fileValue);
playback->setSpacing(0);
playback->setContentsMargins(0, 0, 0, 0);
layout->addLayout(playback);
m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton = new QPushButton(this);
m_suspendResumeButton->setText(statusToString(Status::Iddle)); m_suspendResumeButton->setText(statusToString(Status::Iddle));
@ -71,23 +74,17 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
m_filterBank = new FilterBankWidget(this); m_filterBank = new FilterBankWidget(this);
connect(m_filterBank, SIGNAL(setBypass(bool)), this, SLOT(setBypass(bool))); connect(m_filterBank, SIGNAL(setBypass(bool)), this, SLOT(setBypass(bool)));
layout->addWidget(m_filterBank); layout->addWidget(m_filterBank);
QVBoxLayout *volumeBox = new QVBoxLayout;
m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL);
layout->addWidget(m_pitch); volumeBox->addWidget(m_pitch);
connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int)));
m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL);
layout->addWidget(m_pan); volumeBox->addWidget(m_pan);
connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int)));
m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL);
QHBoxLayout *volumeBox = new QHBoxLayout;
m_volume = new SliderGroup("Vol", 0, 65535, 2, NULL);
volumeBox->addWidget(m_volume); volumeBox->addWidget(m_volume);
connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
m_bus1 = new SliderGroup("Bus 1", 0, 65535, 2, NULL);
volumeBox->addWidget(m_bus1);
connect(m_bus1, SIGNAL(valueChanged(int)), this, SLOT(bus1VolumeChanged(int)));
m_bus2 = new SliderGroup("Bus 2", 0, 65535, 2, NULL);
volumeBox->addWidget(m_bus2);
connect(m_bus2, SIGNAL(valueChanged(int)), this, SLOT(bus2VolumeChanged(int)));
volumeBox->setSpacing(0); volumeBox->setSpacing(0);
volumeBox->setContentsMargins(0, 0, 0, 0); volumeBox->setContentsMargins(0, 0, 0, 0);
layout->addLayout(volumeBox); layout->addLayout(volumeBox);
@ -105,16 +102,6 @@ void AudioLayerWidget::volumeChanged(int value)
emit(uiSliderChanged(m_layer, Slider::Volume, value)); emit(uiSliderChanged(m_layer, Slider::Volume, value));
} }
void AudioLayerWidget::bus1VolumeChanged(int value)
{
emit(uiSliderChanged(m_layer, Slider::Bus1, value));
}
void AudioLayerWidget::bus2VolumeChanged(int value)
{
emit(uiSliderChanged(m_layer, Slider::Bus2, value));
}
void AudioLayerWidget::panChanged(int value) void AudioLayerWidget::panChanged(int value)
{ {
emit(uiSliderChanged(m_layer, Slider::Pan, value)); emit(uiSliderChanged(m_layer, Slider::Pan, value));
@ -234,17 +221,8 @@ void AudioLayerWidget::setCurrentTime(float progress)
void AudioLayerWidget::setFilterParam(int channel, int value) void AudioLayerWidget::setFilterParam(int channel, int value)
{ {
if (channel <= FILTER_BANK_GAIN - FILTER_CHANNELS){
m_filterBank->blockSignals(true); m_filterBank->blockSignals(true);
m_filterBank->setValue(channel, value); m_filterBank->setValue(channel, value);
m_filterBank->blockSignals(false); m_filterBank->blockSignals(false);
} else if (channel == SEND1 - HP_FREQ) {
m_bus1->blockSignals(false);
m_bus1->setValue((value * 256) + 255);
m_bus1->blockSignals(true);
} else if (channel == SEND2 - HP_FREQ) {
m_bus2->blockSignals(false);
m_bus2->setValue(value * 256 + 255);
m_bus2->blockSignals(true);
}
} }

View file

@ -39,8 +39,6 @@ private:
SliderGroup *m_volume; SliderGroup *m_volume;
SliderGroup *m_pan; SliderGroup *m_pan;
SliderGroup *m_pitch; SliderGroup *m_pitch;
SliderGroup *m_bus1;
SliderGroup *m_bus2;
QTimeEdit *m_progressTime; QTimeEdit *m_progressTime;
QTimeEdit *m_totalTimeValue; QTimeEdit *m_totalTimeValue;
QProgressBar *m_progress; QProgressBar *m_progress;
@ -53,8 +51,6 @@ private slots:
void openMediaDialog(); void openMediaDialog();
void toggleSuspendResume(); void toggleSuspendResume();
void volumeChanged(int vol); void volumeChanged(int vol);
void bus1VolumeChanged(int vol);
void bus2VolumeChanged(int vol);
void panChanged(int pan); void panChanged(int pan);
void pitchChanged(int pitch); void pitchChanged(int pitch);
void setBypass(bool value); void setBypass(bool value);

View file

@ -1,5 +1,6 @@
#include "audiowidget.h" #include "audiowidget.h"
#include "dmxPersonality.h"
//#include <cmath>
AudioWidget::AudioWidget(QWidget *parent) : AudioWidget::AudioWidget(QWidget *parent) :
QWidget(parent) QWidget(parent)
@ -22,8 +23,8 @@ AudioWidget::AudioWidget(QWidget *parent) :
for (int j = 0; j < FILTER_CHANNELS; j++) for (int j = 0; j < FILTER_CHANNELS; j++)
m_filtersUpdate[i][j] = -1; m_filtersUpdate[i][j] = -1;
} }
m_layout->setSpacing(2); m_layout->setSpacing(0);
m_layout->setContentsMargins(2, 2, 2, 2); m_layout->setContentsMargins(1, 1, 1, 1);
setLayout(m_layout); setLayout(m_layout);
m_refreshUi = new QTimer(this); m_refreshUi = new QTimer(this);
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
@ -109,6 +110,6 @@ void AudioWidget::refreshUi()
void AudioWidget::filterParamChanged(int layer, int channel, int value) void AudioWidget::filterParamChanged(int layer, int channel, int value)
{ {
m_filtersUpdate[layer][channel - HP_FREQ] = value; m_filtersUpdate[layer][channel - 9] = value;
m_layerUpdate[layer].updated = true; m_layerUpdate[layer].updated = true;
} }

View file

@ -10,9 +10,9 @@
#define FORMAT ma_format_f32 /* Must always be f32. */ #define FORMAT ma_format_f32 /* Must always be f32. */
#define CHANNELS 2 #define CHANNELS 2
#define SAMPLE_RATE 48000 #define SAMPLE_RATE 48000
#define UI_REFRESH_TIME 97 #define UI_REFRESH_TIME 100
#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks #define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks
#define FILTER_CHANNELS 16 // number of dmx channels dedicated to filters by layer #define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer
struct dmxSetting { struct dmxSetting {
int address; int address;
@ -38,9 +38,7 @@ enum Slider
Volume, Volume,
Pan, Pan,
Pitch, Pitch,
Bypass, Bypass
Bus1,
Bus2
}; };
#ifdef __cplusplus #ifdef __cplusplus
@ -73,8 +71,6 @@ struct layerData {
int address; int address;
unsigned int universe; unsigned int universe;
int device; int device;
int bus1Vol;
int bus2Vol;
}; };
#endif // __cplusplus #endif // __cplusplus
#endif // DEFINES_H #endif // DEFINES_H

View file

@ -23,7 +23,7 @@
#define HIGH_FREQ 19 #define HIGH_FREQ 19
#define HIGH_Q 20 #define HIGH_Q 20
#define HIGH_GAIN 21 #define HIGH_GAIN 21
#define FILTER_BANK_GAIN 22 #define FILTER_BANK_GAIN 22 // not implemented yet
#define SEND1 23 #define SEND1 23
#define SEND2 24 #define SEND2 24
#define LAYER_CHANNELS 25 #define LAYER_CHANNELS 25

View file

@ -86,8 +86,7 @@ void FilterBankWidget::setValue(int filter, int value)
result = (double)( value / 32.0f) + 0.1f; result = (double)( value / 32.0f) + 0.1f;
} else if (channel == HIGH_GAIN) { } else if (channel == HIGH_GAIN) {
result = (double)(value / 21.25) - 6.023528412f; result = (double)(value / 21.25) - 6.023528412f;
} else }
result = (double)value;
fb[filter]->setValue(result); fb[filter]->setValue(result);
} }

View file

@ -40,10 +40,15 @@ libreMediaServerAudio::libreMediaServerAudio()
m_updateUi[i][3] = -1; m_updateUi[i][3] = -1;
#endif #endif
} }
if (!m_mae.startEngine(m_layersQty, m_settings->getAudioDeviceId(), m_settings->getAudioDeviceQty())) { if (!m_mae.startEngine(m_layersQty)) {
cout << "Can not start Audio Engine!" << endl; cout << "Can not start Audio Engine!" << endl;
exit(-1); 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); m_ola = new olaThread(this, m_layersQty);
Q_CHECK_PTR(m_ola); Q_CHECK_PTR(m_ola);
m_ola->blockSignals(true); m_ola->blockSignals(true);
@ -96,8 +101,9 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
QString mediaFile = NULL; QString mediaFile = NULL;
int aux; int aux;
if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { if (channel == VOLUME_COARSE || channel == VOLUME_FINE) {
m_mae.volChanged(layer, value); float tmp = value / 65025.0f;
m_updateUi[layer][0] = value; m_mae.volChanged(layer, tmp);
m_updateUi[layer][0] = tmp * 100.0f;
} else if (channel == PAN) { } else if (channel == PAN) {
m_mae.panChanged(layer, value); m_mae.panChanged(layer, value);
m_updateUi[layer][1] = value; m_updateUi[layer][1] = value;
@ -235,7 +241,7 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
{ {
switch (s){ switch (s){
case Slider::Volume: case Slider::Volume:
m_mae.volChanged(layer, value); m_mae.volChanged(layer, float((value / 100.0f)));
break; break;
case Slider::Pan: case Slider::Pan:
m_mae.panChanged(layer, value); m_mae.panChanged(layer, value);
@ -245,13 +251,6 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
break; break;
case Slider::Bypass: case Slider::Bypass:
m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value); m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value);
break;
case Slider::Bus1:
m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND1, value / 255);
break;
case Slider::Bus2:
m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND2, value / 255);
break;
} }
} }

View file

@ -28,6 +28,7 @@ static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFr
ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn); ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn);
} }
} }
//*pFrameCountOut = 0;
ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels);
} }

View file

@ -4,6 +4,10 @@
#define BIAS 0.99f #define BIAS 0.99f
#define FILTER_ORDER 3 #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() {} MiniAudioEngine::MiniAudioEngine() {}
void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
@ -17,78 +21,83 @@ void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const
(void)pInput; (void)pInput;
} }
void MiniAudioEngine::stopEngine() void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{ {
for (uint i = 0; i < m_mae.layersQty; i++) { (void)pDevice;
if (m_mae.mediaLoaded[i]) ma_result result;
ma_sound_uninit(&m_mae.sounds[i]);
ma_uint32 pcmFramesAvailableInRB = 0;
ma_uint32 pcmFramesProcessed = 0;
while (pcmFramesProcessed < frameCount) {
pcmFramesAvailableInRB = ma_pcm_rb_available_read(&aux1Buffer);
if (pcmFramesAvailableInRB == 0) {
break;
} }
for (uint i = 0; i < m_mae.layersQty; i++) { ma_uint32 framesToRead = frameCount - pcmFramesProcessed;
ma_node_uninit(&m_mae.filters[i].input, NULL); if (framesToRead > pcmFramesAvailableInRB) {
ma_hpf_node_uninit(&m_mae.filters[i].hpf, NULL); framesToRead = pcmFramesAvailableInRB;
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++) { void* pReadBuffer = NULL;
if (i > 0) { ma_pcm_rb_acquire_read(&aux1Buffer, &framesToRead, &pReadBuffer);
ma_writer_node_uninit(&m_mae.sendAuxNode[i], NULL); if (pReadBuffer != NULL) {
ma_pcm_rb_uninit(&m_mae.auxBuffers[i]); ma_copy_pcm_frames(pOutput, pReadBuffer, framesToRead, FORMAT, CHANNELS);
ma_pcm_rb_commit_read(&aux1Buffer, framesToRead);
pcmFramesProcessed += framesToRead;
}/* else { break; }*/
} }
ma_engine_uninit(&m_mae.engines[i]); (void)pInput;
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, uint* audioDevicesId, uint audioDevicesQty) void MiniAudioEngine::stopEngine()
{
for (uint i = 0; i < m_layersQty; i++) {
ma_sound_uninit(&m_currentSound[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);
}
//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_context_uninit(&m_context);
ma_resource_manager_uninit(&m_resourceManager);
}
bool MiniAudioEngine::startEngine(uint layers)
{ {
ma_result result; ma_result result;
m_mae.layersQty = layers; m_layersQty = layers;
m_mae.audioDevicesId = audioDevicesId; for (uint i =0; i < m_layersQty; i++) {
m_mae.audioDevicesQty = audioDevicesQty; m_mediaLoaded[i] = false;
for (uint i =0; i < m_mae.layersQty; i++) { m_currentLayerValues[i].status = Status::Iddle;
m_mae.mediaLoaded[i] = false; m_currentLayerValues[i].pan = 128;
m_mae.currentStatus[i].status = Status::Iddle; m_currentLayerValues[i].pitch = 128;
m_mae.currentStatus[i].pan = 128; m_currentLayerValues[i].vol = 0;
m_mae.currentStatus[i].pitch = 128; m_currentLayerValues[i].cursor = 0;
m_mae.currentStatus[i].vol = 0;
m_mae.currentStatus[i].cursor = 0;
} }
result = this->startContext(); result = this->startContext();
if (result != MA_SUCCESS) return false; if (result != MA_SUCCESS) return false;
result = this->getAllAudioDevices(); result = this->getAllAudioDevices();
if (result != MA_SUCCESS) return false; 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; return true;
} }
ma_result MiniAudioEngine::createFilterBank(uint layer) ma_result MiniAudioEngine::createFilterBank(int id, uint layer)
{ {
ma_result result; ma_result result;
ma_node_graph *ng = ma_engine_get_node_graph(&m_mae.engines[0]); ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]);
ma_node *endpoint = ma_engine_get_endpoint(&m_mae.engines[0]); ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]);
filterBank *fb = &m_mae.filters[layer]; filterBank *fb = &m_filterBank[id][layer];
ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS);
result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input); result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input);
@ -131,12 +140,13 @@ ma_result MiniAudioEngine::createFilterBank(uint layer)
cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl; cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl;
return result; return result;
} }
splitterConfig.outputBusCount = m_mae.audioDevicesQty;
result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output); result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to init output node." << endl; cout << "ERROR " << result << ": Failed to init output node." << endl;
return result; return result;
} }
result = ma_node_attach_output_bus(&fb->input, 0, &fb->hpf, 0); result = ma_node_attach_output_bus(&fb->input, 0, &fb->hpf, 0);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach input node." << endl; cout << "ERROR " << result << ": Failed to attach input node." << endl;
@ -173,143 +183,137 @@ ma_result MiniAudioEngine::createFilterBank(uint layer)
cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl;
return result; return result;
} }
if (m_mae.audioDevicesQty == 1) { if (id == 0) {
result = ma_node_attach_output_bus(&fb->output, 0, endpoint, 0); result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output to endpoint." << endl; cout << "ERROR " << result << ": Failed to attach output node to engine." << endl;
return result; return result;
} }
} else { result = ma_node_attach_output_bus(&fb->output, 1, &m_sendToAux[id], 1);
result = ma_node_attach_output_bus(&fb->output, 0, &m_mae.sendAuxNode[1], 0);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl;
return result; 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; return result;
} }
ma_result MiniAudioEngine::setNodeGraph() { ma_result MiniAudioEngine::setNodeGraph(int id) {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
uint i = 0;
ma_node_graph *ng = ma_engine_get_node_graph(&m_mae.engines[0]); if (id == 0) {
for (uint i = 1; i < m_mae.audioDevicesQty; i++) { ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]);
size_t sizeInFrames = SAMPLE_RATE; size_t sizeInFrames = SAMPLE_RATE; // ma_get_bytes_per_frame(FORMAT, CHANNELS);
result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &m_mae.auxBuffers[i]); result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &aux1Buffer);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
printf("Failed to initialize ring buffer.\n"); printf("Failed to initialize ring buffer.\n");
return result; return result;
} }
ma_silence_pcm_frames(m_mae.auxBuffers[i].rb.pBuffer, sizeInFrames, FORMAT, CHANNELS); ma_silence_pcm_frames(aux1Buffer.rb.pBuffer, sizeInFrames, FORMAT, CHANNELS);
ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &m_mae.auxBuffers[i]); ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &aux1Buffer);
result = ma_writer_node_init(ng, &writerConfig, NULL, &m_mae.sendAuxNode[i]); result = ma_writer_node_init(ng, &writerConfig, NULL, &m_sendToAux[id]);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to init writer node." << endl; cout << "ERROR " << result << ": Failed to init writer node." << endl;
return result; return result;
} }
// esto va a dar problemas al sumar en el envío 0 una vez por cad envío extra. result = ma_node_attach_output_bus(&m_sendToAux[id], 0, ma_engine_get_endpoint(&m_engine[id]), 0); // Pull API
// 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) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach writer node." << endl; cout << "ERROR " << result << ": Failed to attach writer node." << endl;
return result; 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); return (result);
} }
ma_result MiniAudioEngine::startDevices() bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_device_config deviceConfig; ma_device_config deviceConfig;
ma_engine_config engineConfig; ma_engine_config engineConfig;
m_devicesSelected = nb;
for (uint internalId = 0; internalId < nb; internalId++) {
deviceConfig = ma_device_config_init(ma_device_type_duplex); deviceConfig = ma_device_config_init(ma_device_type_duplex);
deviceConfig.capture.format = m_mae.resourceManager.config.decodedFormat; deviceConfig.capture.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id;
deviceConfig.capture.format = m_resourceManager.config.decodedFormat;
deviceConfig.capture.channels = CHANNELS; deviceConfig.capture.channels = CHANNELS;
deviceConfig.playback.channels = CHANNELS;
deviceConfig.capture.shareMode = ma_share_mode_shared; deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.format = m_mae.resourceManager.config.decodedFormat; deviceConfig.playback.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id;
deviceConfig.sampleRate = m_mae.resourceManager.config.decodedSampleRate; deviceConfig.playback.format = m_resourceManager.config.decodedFormat;
deviceConfig.playback.channels = CHANNELS;
deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate;
if (internalId == 0)
deviceConfig.dataCallback = audioDataCallback; deviceConfig.dataCallback = audioDataCallback;
engineConfig = ma_engine_config_init(); else if (internalId == 1)
engineConfig.pResourceManager = &m_mae.resourceManager; deviceConfig.dataCallback = audioDataCallback1;
engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 25; deviceConfig.pUserData = &m_engine[internalId];
engineConfig.noAutoStart = MA_TRUE; result = ma_device_init(&m_context, &deviceConfig, &m_device[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) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to initialize audio device " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; cout << "Error " << result << ": Failed to initialize audio device " << m_pPlaybackDeviceInfos[*systemId].name << endl;
return result; return false;
} }
engineConfig.pDevice = &m_mae.devices[internalId]; engineConfig = ma_engine_config_init();
result = ma_engine_init(&engineConfig, &m_mae.engines[internalId]); 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]);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to initialize audio engine" << endl; cout << "Error " << result << ": Failed to initialize audio engine" << endl;
return result; return false;
} }
cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << m_mae.audioDevicesId[internalId] << " " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; result = this->setNodeGraph(internalId);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to set node graph " << systemId[internalId] << endl;
return false;
} }
return result; 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;
} }
ma_result MiniAudioEngine::startContext() ma_result MiniAudioEngine::startContext()
{ {
ma_result result; ma_result result;
ma_resource_manager_config resourceManagerConfig = ma_resource_manager_config_init(); m_resourceManagerConfig = ma_resource_manager_config_init();
resourceManagerConfig.decodedFormat = FORMAT; m_resourceManagerConfig.decodedFormat = FORMAT;
resourceManagerConfig.decodedChannels = CHANNELS; m_resourceManagerConfig.decodedChannels = CHANNELS;
resourceManagerConfig.decodedSampleRate = SAMPLE_RATE; m_resourceManagerConfig.decodedSampleRate = SAMPLE_RATE;
resourceManagerConfig.jobThreadCount = MAX_LAYERS; m_resourceManagerConfig.jobThreadCount = 4;
result = ma_resource_manager_init(&resourceManagerConfig, &m_mae.resourceManager); result = ma_resource_manager_init(&m_resourceManagerConfig, &m_resourceManager);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to initialize audio resource manager." << endl; cout << "Error " << result << ": Failed to initialize audio resource manager." << endl;
return result; return result;
} }
result = ma_context_init(NULL, 0, NULL, &m_mae.context); result = ma_context_init(NULL, 0, NULL, &m_context);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to initialize audio context." << endl; cout << "Error " << result << ": Failed to initialize audio context." << endl;
} }
@ -321,15 +325,15 @@ ma_result MiniAudioEngine::getAllAudioDevices()
{ {
ma_result result; ma_result result;
result = ma_context_get_devices(&m_mae.context, &m_mae.pPlaybackDeviceInfos, &m_mae.playbackDeviceCount, NULL, NULL); result = ma_context_get_devices(&m_context, &m_pPlaybackDeviceInfos, &m_playbackDeviceCount, NULL, NULL);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to enumerate playback devices." << endl; cout << "Error " << result << ": Failed to enumerate playback devices." << endl;
ma_context_uninit(&m_mae.context); ma_context_uninit(&m_context);
return result; return result;
} }
cout << "Audio devices available:" << endl; cout << "Audio devices available:" << endl;
for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_mae.playbackDeviceCount; iAvailableDevice += 1) { for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_playbackDeviceCount; iAvailableDevice += 1) {
cout << iAvailableDevice << " : " << m_mae.pPlaybackDeviceInfos[iAvailableDevice].name << endl; cout << iAvailableDevice << " : " << m_pPlaybackDeviceInfos[iAvailableDevice].name << endl;
} }
return result; return result;
} }
@ -338,26 +342,28 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice)
{ {
ma_result result; ma_result result;
if (m_mae.mediaLoaded[layer] == true) // - 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)
{ {
ma_sound_uninit(&m_mae.sounds[layer]); ma_sound_uninit(&m_currentSound[layer]);
m_mae.mediaLoaded[layer] = false; m_mediaLoaded[layer] = false;
} }
result = ma_sound_init_from_file(&m_mae.engines[0], file, \ result = ma_sound_init_from_file(&m_engine[audioDevice], file, \
MA_SOUND_FLAG_NO_SPATIALIZATION \ MA_SOUND_FLAG_NO_SPATIALIZATION \
, NULL, NULL, &m_mae.sounds[layer]); , NULL, NULL, &m_currentSound[layer]);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to load file " << file << endl; cout << "Error " << result << ": Failed to load file " << file << endl;
return result; return result;
} }
result = ma_node_attach_output_bus(&m_mae.sounds[layer], 0, &m_mae.filters[layer].input, 0); result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].input, 0);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl; cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl;
return result; //return result;
} }
m_mae.mediaLoaded[layer] = true; m_mediaLoaded[layer] = true;
this->refreshValues(layer); this->refreshValues(layer);
m_mae.currentStatus[layer].media = file; m_currentLayerValues[layer].media = file;
return result; return result;
} }
@ -366,9 +372,9 @@ float MiniAudioEngine::getDuration(int layer)
ma_result result; ma_result result;
float ret; float ret;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return MA_DOES_NOT_EXIST; return MA_DOES_NOT_EXIST;
result = ma_sound_get_length_in_seconds(&m_mae.sounds[layer], &ret); result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
return result; return result;
} }
@ -380,9 +386,9 @@ float MiniAudioEngine::getCursor(int layer)
ma_result result; ma_result result;
float ret = 0; float ret = 0;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return MA_DOES_NOT_EXIST; return MA_DOES_NOT_EXIST;
result = ma_sound_get_cursor_in_seconds(&m_mae.sounds[layer], &ret); result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret);
if (result != MA_SUCCESS) if (result != MA_SUCCESS)
{ {
cout << "Error" << result << ": Can not get cursor " << layer << endl; cout << "Error" << result << ": Can not get cursor " << layer << endl;
@ -397,72 +403,69 @@ ma_result MiniAudioEngine::printFormatInfo(int layer)
ma_uint32 channels; ma_uint32 channels;
ma_uint32 sampleRate; ma_uint32 sampleRate;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return MA_DOES_NOT_EXIST; return MA_DOES_NOT_EXIST;
ma_result result = ma_sound_get_data_format(&m_mae.sounds[layer], \ ma_result result = ma_sound_get_data_format(&m_currentSound[layer], \
&format, &channels, &sampleRate, NULL, 0); &format, &channels, &sampleRate, NULL, 0);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to get data format " << layer; cout << "Error " << result << ": Failed to get data format " << layer;
cout << endl; cout << endl;
} else { } else {
cout << "Layer:" << layer << " "; cout << "Layer:" << layer << " ";
cout << m_mae.currentStatus[layer].media.toLatin1().data(); cout << m_currentLayerValues[layer].media.toLatin1().data();
cout << " samples/sec:" << sampleRate << " format:" << format; cout << " samples/sec:" << sampleRate << " format:" << format;
cout << " channels:" << channels << endl; cout << " channels:" << channels << endl;
} }
return result; return result;
} }
// Expects between 0 and 65535 vol value // Expects between 0 and 1 vol value
void MiniAudioEngine::volChanged(int layer, int vol) void MiniAudioEngine::volChanged(int layer, float vol)
{ {
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return; return;
float db = ((float)vol / 771.0f) - 85.0f; if (vol >= 1)
if (db <= -85.0f) { vol = 0.99f;
db = 0; ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, pow(vol, 3), FADE_TIME);
} else m_currentLayerValues[layer].vol = vol;
db = ma_volume_db_to_linear(db);
ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME);
m_mae.currentStatus[layer].vol = vol;
} }
void MiniAudioEngine::panChanged(int layer, float value) void MiniAudioEngine::panChanged(int layer, float value)
{ {
float result; float result;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return; return;
result = (value / 128.0) - 1.0; result = (value / 128.0) - 1.0;
ma_sound_group_set_pan(&m_mae.sounds[layer], result); ma_sound_group_set_pan(&m_currentSound[layer], result);
m_mae.currentStatus[layer].pan = value; m_currentLayerValues[layer].pan = value;
} }
void MiniAudioEngine::pitchChanged(int layer, float value) void MiniAudioEngine::pitchChanged(int layer, float value)
{ {
float pitch; float pitch;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return; return;
pitch = value / 128.0; pitch = value / 128.0;
ma_sound_group_set_pitch(&m_mae.sounds[layer], pitch); ma_sound_group_set_pitch(&m_currentSound[layer], pitch);
m_mae.currentStatus[layer].pitch = value; m_currentLayerValues[layer].pitch = value;
} }
ma_result MiniAudioEngine::playbackChanged(int layer, Status status) ma_result MiniAudioEngine::playbackChanged(int layer, Status status)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return MA_DOES_NOT_EXIST; return MA_DOES_NOT_EXIST;
bool loop = false; bool loop = false;
switch (status) { switch (status) {
case Status::Paused: case Status::Paused:
result = ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME);
break; break;
case Status::Stopped: case Status::Stopped:
ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME);
result = this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); result = this->seekToCursor(layer, m_currentLayerValues[layer].cursor);
break; break;
case Status::PlayingLoop: case Status::PlayingLoop:
loop = true; loop = true;
@ -470,18 +473,18 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status)
case Status::PlayingFolder: case Status::PlayingFolder:
case Status::PlayingFolderLoop: case Status::PlayingFolderLoop:
case Status::PlayingFolderRandom: case Status::PlayingFolderRandom:
ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0); ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0);
ma_sound_set_looping(&m_mae.sounds[layer], loop); ma_sound_set_looping(&m_currentSound[layer], loop);
result = ma_sound_start(&m_mae.sounds[layer]); result = ma_sound_start(&m_currentSound[layer]);
if (m_mae.currentStatus[layer].cursor != 0) { if (m_currentLayerValues[layer].cursor != 0) {
usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line? usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line?
} }
this->volChanged(layer, m_mae.currentStatus[layer].vol); this->volChanged(layer, m_currentLayerValues[layer].vol);
default: default:
break; break;
} }
if (result == MA_SUCCESS) if (result == MA_SUCCESS)
m_mae.currentStatus[layer].status = status; m_currentLayerValues[layer].status = status;
return result; return result;
} }
@ -490,13 +493,13 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor)
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
ma_uint64 end, start; ma_uint64 end, start;
if (m_mae.mediaLoaded[layer] == false) if (m_mediaLoaded[layer] == false)
return MA_DOES_NOT_EXIST; return MA_DOES_NOT_EXIST;
result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end);
if (result != MA_SUCCESS) { return result; } if (result != MA_SUCCESS) { return result; }
start = (cursor * end) / 65025; start = (cursor * end) / 65025;
result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], start); result = ma_sound_seek_to_pcm_frame(&m_currentSound[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? //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?
return (result); return (result);
} }
@ -504,30 +507,30 @@ ma_result MiniAudioEngine::setCursor(int layer, int cursor)
{ {
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
m_mae.currentStatus[layer].cursor = cursor; m_currentLayerValues[layer].cursor = cursor;
result = this->seekToCursor(layer, cursor); result = this->seekToCursor(layer, cursor);
return (result); return (result);
} }
Status MiniAudioEngine::getStatus(int layer) Status MiniAudioEngine::getStatus(int layer)
{ {
return m_mae.currentStatus[layer].status; return m_currentLayerValues[layer].status;
} }
void MiniAudioEngine::refreshValues(int layer) void MiniAudioEngine::refreshValues(int layer)
{ {
this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); this->seekToCursor(layer, m_currentLayerValues[layer].cursor);
this->panChanged(layer, m_mae.currentStatus[layer].pan); this->panChanged(layer, m_currentLayerValues[layer].pan);
this->volChanged(layer, m_mae.currentStatus[layer].vol); this->volChanged(layer, m_currentLayerValues[layer].vol);
this->pitchChanged(layer, m_mae.currentStatus[layer].pitch); this->pitchChanged(layer, m_currentLayerValues[layer].pitch);
this->playbackChanged(layer, m_mae.currentStatus[layer].status); this->playbackChanged(layer, m_currentLayerValues[layer].status);
} }
ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int channel, int value) ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int channel, int value)
{ {
(void)audioDevice;
ma_result result = MA_SUCCESS; ma_result result = MA_SUCCESS;
filterBank *fb = &m_mae.filters[layer];
filterBank *fb = &m_filterBank[audioDevice][layer];
if (channel == HP_FREQ) { if (channel == HP_FREQ) {
fb->hpfConfig.hpf.cutoffFrequency = double((value * 1.31) + 16.0f); // 16 - 350 fb->hpfConfig.hpf.cutoffFrequency = double((value * 1.31) + 16.0f); // 16 - 350
@ -621,23 +624,13 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch
return result; return result;
} }
} else if (channel == SEND1) { } else if (channel == SEND1) {
float db = ((float)value / 3.0f) - 85.0f; ma_node_set_output_bus_volume(&fb->output, 0, pow((value / 255.0f), 2));
if (db <= -85.0f) {
db = 0;
} else
db = ma_volume_db_to_linear(db);
ma_node_set_output_bus_volume(&fb->output, 0, db);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed set Send 1 Volume." << endl; cout << "ERROR " << result << ": Failed set Send 1 Volume." << endl;
return result; return result;
} }
} else if (channel == SEND2) { } else if (channel == SEND2) {
float db = ((float)value / 3.0f) - 85.0f; ma_node_set_output_bus_volume(&fb->output, 1, pow((value / 255.0f), 2));
if (db <= -85.0f) {
db = 0;
} else
db = ma_volume_db_to_linear(db);
ma_node_set_output_bus_volume(&fb->output, 1, db);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed set Send 2 Volume." << endl; cout << "ERROR " << result << ": Failed set Send 2 Volume." << endl;
} }
@ -648,8 +641,7 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch
bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass)
{ {
(void)audioDevice; filterBank *fb = &m_filterBank[audioDevice][layer];
filterBank *fb = &m_mae.filters[layer];
if (bypass) { if (bypass) {
ma_node_set_output_bus_volume(&fb->input, 1, 1.0f); ma_node_set_output_bus_volume(&fb->input, 1, 1.0f);

View file

@ -15,6 +15,7 @@
using namespace std; using namespace std;
#include "defines.h" #include "defines.h"
typedef struct typedef struct
{ {
ma_splitter_node input; ma_splitter_node input;
@ -29,44 +30,36 @@ typedef struct
ma_hishelf_node hishelf; ma_hishelf_node hishelf;
ma_hishelf_node_config hishelfConfig; ma_hishelf_node_config hishelfConfig;
ma_splitter_node output; ma_splitter_node output;
ma_writer_node send1;
ma_data_source_node return1;
ma_audio_buffer_ref supplyReturn1;
} filterBank; } filterBank;
typedef struct typedef struct
{ {
ma_engine engines[MAX_AUDIODEVICES]; ma_engine m_engine[MAX_AUDIODEVICES];
ma_device devices[MAX_AUDIODEVICES]; filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS];
filterBank filters[MAX_LAYERS]; ma_writer_node m_sendAux1[MAX_LAYERS];
ma_writer_node sendAuxNode[MAX_AUDIODEVICES]; ma_pcm_rb *aux1Buffer;
ma_pcm_rb auxBuffers[MAX_AUDIODEVICES]; } audioObjects;
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 class MiniAudioEngine
{ {
friend class libreMediaServerAudio; friend class libreMediaServerAudio;
static ma_pcm_rb *rb;
public: public:
MiniAudioEngine(); MiniAudioEngine();
void stopEngine(); void stopEngine();
bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty); bool startEngine(uint layersQty);
bool startDevice(uint *id, uint nb);
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); 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: protected:
ma_result loadMedia(int layer, char *media, uint audioDevice); ma_result loadMedia(int layer, char *media, uint audioDevice);
void volChanged(int layer, int vol); void volChanged(int layer, float vol);
void panChanged(int layer, float pan); void panChanged(int layer, float pan);
void pitchChanged(int layer, float pitch); void pitchChanged(int layer, float pitch);
ma_result playbackChanged(int layer, Status status); ma_result playbackChanged(int layer, Status status);
@ -76,21 +69,33 @@ protected:
float getCursor(int layer); float getCursor(int layer);
Status getStatus(int layer); Status getStatus(int layer);
inline float getVol(int layer) { inline float getVol(int layer) {
return ma_sound_get_volume(&m_mae.sounds[layer]); } return ma_sound_get_volume(&m_currentSound[layer]); }
inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; } inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; }
ma_result filterParamChanged(int layer, int audioDevice, int channel, int value); ma_result filterParamChanged(int layer, int audioDevice, int channel, int value);
bool setBypass(int audioDevice, int layer, bool bypass);
private: private:
MAE m_mae; 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;
ma_result startDevices();
ma_result getAllAudioDevices(); ma_result getAllAudioDevices();
ma_result startContext(); ma_result startContext();
void refreshValues(int layer); void refreshValues(int layer);
ma_result seekToCursor(int layer, int cursor); ma_result seekToCursor(int layer, int cursor);
ma_result setNodeGraph(); ma_result setNodeGraph(int id);
ma_result createFilterBank(uint layer); ma_result createFilterBank(int id, uint layer);
}; };
#endif // MINIAUDIOENGINE_H #endif // MINIAUDIOENGINE_H

View file

@ -1,5 +1,5 @@
#include "slidergroup.h" #include "slidergroup.h"
#include <cmath>
#include <QWidget> #include <QWidget>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -39,10 +39,6 @@ SliderGroup::SliderGroup(QString name,
valueBox.setFocusPolicy(Qt::NoFocus); valueBox.setFocusPolicy(Qt::NoFocus);
valueBox.setButtonSymbols(QAbstractSpinBox::NoButtons); valueBox.setButtonSymbols(QAbstractSpinBox::NoButtons);
valueBox.setMinimumWidth(50); valueBox.setMinimumWidth(50);
if (decimals) {
valueBox.setRange(-84.0f, 0.0f);
valueBox.setSpecialValueText("-inf");
} else
valueBox.setRange(min, max); valueBox.setRange(min, max);
valueBox.setValue(0); valueBox.setValue(0);
valueBox.setDecimals(decimals); valueBox.setDecimals(decimals);
@ -55,7 +51,7 @@ SliderGroup::SliderGroup(QString name,
layout->addWidget(&slider); layout->addWidget(&slider);
layout->addWidget(&valueBox); layout->addWidget(&valueBox);
this->setStyleSheet("border: 1px solid #5a4855;" this->setStyleSheet("border: 1px solid #5a4855;"
"width: 60px;" "width: 50px;"
"margin: 0px;" "margin: 0px;"
"background-color: #383034;" "background-color: #383034;"
); );
@ -67,27 +63,17 @@ SliderGroup::SliderGroup(QString name,
void SliderGroup::sliderValueChanged(int value) void SliderGroup::sliderValueChanged(int value)
{ {
valueBox.blockSignals(true); valueBox.blockSignals(true);
float db = ((float)value / 771.0f) - 85.0f; valueBox.setValue(value);
if (db <= -84.5f) {
valueBox.setSpecialValueText("-inf");
} else
valueBox.setValue(db);
valueBox.blockSignals(false); valueBox.blockSignals(false);
emit valueChanged(value); emit valueChanged(value);
}; };
void SliderGroup::setValue(float value) void SliderGroup::setValue(float value)
{ {
float db;
slider.blockSignals(true); slider.blockSignals(true);
valueBox.blockSignals(true); valueBox.blockSignals(true);
if (int(value) != slider.value()) if (int(value) != slider.value())
slider.setValue(value); slider.setValue(value);
if (valueBox.decimals()) {
db = (float)(value / 771.0f) - 85.0f;
valueBox.setValue(db);
} else
valueBox.setValue(value); valueBox.setValue(value);
slider.blockSignals(false); slider.blockSignals(false);
valueBox.blockSignals(false); valueBox.blockSignals(false);