Compare commits

...

3 commits

Author SHA1 Message Date
snt
200dcf86d4 volumen y envíos en logarítmico auténtico, entre -85dB y 0.
SLiders en UI para los envíos (sólo 2, estáticos, hay que meter un bucle
con el número de envíos).
2024-05-21 18:17:55 +02:00
snt
f0f6e595fb cambiada curva de volume de cúbia a cuadrática, en pruebas a ver si es
suficiente.
valuebox de volumen en decibelios.
2024-05-20 20:08:26 +02:00
snt
5d56921aeb 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.
2024-05-20 19:00:05 +02:00
12 changed files with 345 additions and 294 deletions

View file

@ -46,6 +46,10 @@ v 0.2.1
- Hardening: check return errors, try/catch exceptions, i'm too happy....
- Tests: errors on wrong conf file.
- 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:
- 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,4 +1,5 @@
#include "audiolayerwidget.h"
#include "dmxPersonality.h"
#include <QBoxLayout>
#include <QFileDialog>
@ -11,7 +12,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
{
QVBoxLayout *layout = new QVBoxLayout;
QVBoxLayout *playback = new QVBoxLayout;
m_folderValue = new ClickableLabel;
m_folderValue->setMaximumWidth(300);
m_folderValue->setAlignment(Qt::AlignLeft);
@ -19,7 +19,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
"color: white;"
"background-color: black;"
);
playback->addWidget(m_folderValue);
layout->addWidget(m_folderValue);
m_fileValue = new ClickableLabel;
connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog()));
connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog()));
@ -29,10 +29,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
"color: white;"
"background-color: black;"
);
playback->addWidget(m_fileValue);
playback->setSpacing(0);
playback->setContentsMargins(0, 0, 0, 0);
layout->addLayout(playback);
layout->addWidget(m_fileValue);
m_suspendResumeButton = new QPushButton(this);
m_suspendResumeButton->setText(statusToString(Status::Iddle));
@ -74,17 +71,23 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
m_filterBank = new FilterBankWidget(this);
connect(m_filterBank, SIGNAL(setBypass(bool)), this, SLOT(setBypass(bool)));
layout->addWidget(m_filterBank);
QVBoxLayout *volumeBox = new QVBoxLayout;
m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL);
volumeBox->addWidget(m_pitch);
layout->addWidget(m_pitch);
connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int)));
m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL);
volumeBox->addWidget(m_pan);
layout->addWidget(m_pan);
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);
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->setContentsMargins(0, 0, 0, 0);
layout->addLayout(volumeBox);
@ -102,6 +105,16 @@ void AudioLayerWidget::volumeChanged(int 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)
{
emit(uiSliderChanged(m_layer, Slider::Pan, value));
@ -157,9 +170,9 @@ void AudioLayerWidget::openMediaDialog()
// from DMX signals
void AudioLayerWidget::setVol(float vol)
{
m_volume->blockSignals(true);
m_volume->setValue(vol);
m_volume->blockSignals(false);
m_volume->blockSignals(true);
m_volume->setValue(vol);
m_volume->blockSignals(false);
}
void AudioLayerWidget::setPan(int pan)
@ -221,8 +234,17 @@ void AudioLayerWidget::setCurrentTime(float progress)
void AudioLayerWidget::setFilterParam(int channel, int value)
{
m_filterBank->blockSignals(true);
m_filterBank->setValue(channel, value);
m_filterBank->blockSignals(false);
if (channel <= FILTER_BANK_GAIN - FILTER_CHANNELS){
m_filterBank->blockSignals(true);
m_filterBank->setValue(channel, value);
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,6 +39,8 @@ private:
SliderGroup *m_volume;
SliderGroup *m_pan;
SliderGroup *m_pitch;
SliderGroup *m_bus1;
SliderGroup *m_bus2;
QTimeEdit *m_progressTime;
QTimeEdit *m_totalTimeValue;
QProgressBar *m_progress;
@ -51,6 +53,8 @@ private slots:
void openMediaDialog();
void toggleSuspendResume();
void volumeChanged(int vol);
void bus1VolumeChanged(int vol);
void bus2VolumeChanged(int vol);
void panChanged(int pan);
void pitchChanged(int pitch);
void setBypass(bool value);

View file

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

View file

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

View file

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

View file

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

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);
@ -101,9 +96,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
QString mediaFile = NULL;
int aux;
if (channel == VOLUME_COARSE || channel == VOLUME_FINE) {
float tmp = value / 65025.0f;
m_mae.volChanged(layer, tmp);
m_updateUi[layer][0] = tmp * 100.0f;
m_mae.volChanged(layer, value);
m_updateUi[layer][0] = value;
} else if (channel == PAN) {
m_mae.panChanged(layer, value);
m_updateUi[layer][1] = value;
@ -241,7 +235,7 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
{
switch (s){
case Slider::Volume:
m_mae.volChanged(layer, float((value / 100.0f)));
m_mae.volChanged(layer, value);
break;
case Slider::Pan:
m_mae.panChanged(layer, value);
@ -251,6 +245,13 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
break;
case Slider::Bypass:
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,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);
}
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,69 +397,72 @@ 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;
}
return result;
}
// Expects between 0 and 1 vol value
void MiniAudioEngine::volChanged(int layer, float vol)
// Expects between 0 and 65535 vol value
void MiniAudioEngine::volChanged(int layer, int 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;
float db = ((float)vol / 771.0f) - 85.0f;
if (db <= -85.0f) {
db = 0;
} else
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)
{
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 +470,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 +490,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 +504,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
@ -624,13 +621,23 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch
return result;
}
} else if (channel == SEND1) {
ma_node_set_output_bus_volume(&fb->output, 0, pow((value / 255.0f), 2));
float db = ((float)value / 3.0f) - 85.0f;
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) {
cout << "ERROR " << result << ": Failed set Send 1 Volume." << endl;
return result;
}
} else if (channel == SEND2) {
ma_node_set_output_bus_volume(&fb->output, 1, pow((value / 255.0f), 2));
float db = ((float)value / 3.0f) - 85.0f;
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) {
cout << "ERROR " << result << ": Failed set Send 2 Volume." << endl;
}
@ -641,7 +648,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,36 +29,44 @@ 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);
void volChanged(int layer, float vol);
void volChanged(int layer, int vol);
void panChanged(int layer, float pan);
void pitchChanged(int layer, float pitch);
ma_result playbackChanged(int layer, Status status);
@ -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

View file

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