Compare commits
No commits in common. "0d29dda4c1e2ea5f4562df282c4ddfa8d6251fb2" and "53bcb38455cb9aae86219910cd8b4b7505ebf3b2" have entirely different histories.
0d29dda4c1
...
53bcb38455
11 changed files with 82 additions and 143 deletions
|
@ -1,10 +1,10 @@
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
LibreMediaServer Audio - An open source media server for arts and performing.
|
Libre Media Server Audio - An Open source Media Server for arts and performing.
|
||||||
(c) Criptomart - Santiago Noreña 2012-2024 <lms@criptomart.net>
|
(c) Criptomart - Santiago Noreña 2012-2024 <lms@criptomart.net>
|
||||||
https://git.criptomart.net/libremediaserver
|
https://git.criptomart.net/libremediaserver
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
|
|
||||||
LibreMediaServer Changelog
|
Libre Media Server ChangeLog
|
||||||
|
|
||||||
v 0.2.0 Antígona (26/05/2024)
|
v 0.2.0 Antígona (26/05/2024)
|
||||||
+ Change audio engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing.
|
+ Change audio engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing.
|
||||||
|
@ -20,7 +20,9 @@ v 0.2.0 Antígona (26/05/2024)
|
||||||
+ OlaThread send double channels (volume, entry point, load media) only once for each dmx frame buffer.
|
+ OlaThread send double channels (volume, entry point, load media) only once for each dmx frame buffer.
|
||||||
+ Terminal mode without graphical interface. All audio methods has been refactorized out of QWidget world.
|
+ Terminal mode without graphical interface. All audio methods has been refactorized out of QWidget world.
|
||||||
+ Compilation without GUI (-DNOGUI).
|
+ Compilation without GUI (-DNOGUI).
|
||||||
|
+ New Status "Iddle" in playbacks if is not loaded.
|
||||||
+ New DMX personality version, better sort for audio needs (first load media, set vol, pan, etc, last playback order);
|
+ New DMX personality version, better sort for audio needs (first load media, set vol, pan, etc, last playback order);
|
||||||
|
+ Refresh layer values when it loads a new sound file.
|
||||||
+ No QtSignals for sending data, better performance about 20% in my machine. Now, libremediaserver only updates values in AudioWidget, ui refresh is doing with a timer in audiowidget, so there is not problems between graphical and ola thread (the callback). Signals are used only from Ui to libreMediaServer to notify user interactions and Qtimers.
|
+ No QtSignals for sending data, better performance about 20% in my machine. Now, libremediaserver only updates values in AudioWidget, ui refresh is doing with a timer in audiowidget, so there is not problems between graphical and ola thread (the callback). Signals are used only from Ui to libreMediaServer to notify user interactions and Qtimers.
|
||||||
+ Load media files from ui clicking in the media labels.
|
+ Load media files from ui clicking in the media labels.
|
||||||
+ New Play Modes:
|
+ New Play Modes:
|
||||||
|
@ -29,7 +31,6 @@ v 0.2.0 Antígona (26/05/2024)
|
||||||
- Play all medias in one folder randomly.
|
- Play all medias in one folder randomly.
|
||||||
+ Multi audio devices output.
|
+ Multi audio devices output.
|
||||||
+ Vumeter for each layer
|
+ Vumeter for each layer
|
||||||
+ Show device name on Ui and ouput bus slider.
|
|
||||||
|
|
||||||
v 0.1.3 Leúcade (19/04/2024)
|
v 0.1.3 Leúcade (19/04/2024)
|
||||||
+ Ubuntu 22.04 jammy.
|
+ Ubuntu 22.04 jammy.
|
||||||
|
|
|
@ -6,32 +6,38 @@ https://git.criptomart.net/libremediaserver
|
||||||
|
|
||||||
Libre Media Server Roadmap
|
Libre Media Server Roadmap
|
||||||
|
|
||||||
v 0.3.0
|
v 0.2.x
|
||||||
- Ui/Ux: skin, style.
|
- skin, UI/UX
|
||||||
- Ui/Ux; Keyboards strokes.
|
|
||||||
- Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante.
|
|
||||||
- Ui/Ux: seek cursor playback
|
|
||||||
- live input.
|
- live input.
|
||||||
- remove ola and use sACN directly.
|
- insertar/bypass/eliminar audio procesadores sin reiniciar por capa y master. (compresor, equs).
|
||||||
|
- FX en capas master para que se puedan usar como envíos de auxiliar.
|
||||||
|
- Enroutado de masters en otros masters (retorno de efectos).
|
||||||
|
|
||||||
|
v 0.2.2
|
||||||
|
- Use sACN directly.
|
||||||
+ la instalación de OLA es mediante compilación, el repo de paquetes no está actualizado, nada user-friendly.
|
+ la instalación de OLA es mediante compilación, el repo de paquetes no está actualizado, nada user-friendly.
|
||||||
+ hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente.
|
+ hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente.
|
||||||
+ https://github.com/ETCLabs/sACN
|
+ https://github.com/ETCLabs/sACN
|
||||||
- Qt6.
|
- Qt6.
|
||||||
- CIPT/MSex.
|
- Audio processing (eq, rev, compresor, ...) by master and layer.
|
||||||
|
- CIPT/MSex, send icons play/pause/stop.
|
||||||
- Rasp build.
|
- Rasp build.
|
||||||
- Octopus Sound Card support (6 outputs - 8 inputs).
|
- Octopus Sound Card support (6 outputs - 8 inputs).
|
||||||
|
|
||||||
|
v 0.2.1
|
||||||
|
- mute/panic on layer.
|
||||||
- Master Bus Layer:
|
- Master Bus Layer:
|
||||||
|
- each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3.
|
||||||
|
- each layer will have one volume dmx channel for each bus layer. One aux "Send" prefader.
|
||||||
- mute/panic.
|
- mute/panic.
|
||||||
- fader + value
|
- fader + value
|
||||||
- pan
|
- pan.
|
||||||
- magicq personality .hed
|
- magicq .hed
|
||||||
- audio device linked, outputs will be redirected there.
|
- audio device linked, outputs will be redirected there.
|
||||||
- dmx address + universe settings.
|
- dmx address + universe settings.
|
||||||
- compresor/limiter.
|
- Rose noise and sine generator in menu to test system.
|
||||||
- Layer:
|
- Ui/Ux; Keyboards strokes.
|
||||||
- audio procesadores (compresor, reveb, delay).
|
- Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante.
|
||||||
- mute/panic.
|
|
||||||
- Rose noise and sine generator.
|
|
||||||
- Logs, verbosity, timestamp.
|
- Logs, verbosity, timestamp.
|
||||||
- New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH
|
- New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH
|
||||||
- SettingsDialog.
|
- SettingsDialog.
|
||||||
|
@ -39,4 +45,8 @@ v 0.3.0
|
||||||
- ¿Exit Point? is it needed?
|
- ¿Exit Point? is it needed?
|
||||||
- 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
|
||||||
- ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer
|
- ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer
|
||||||
|
|
||||||
|
v0.2.0:
|
||||||
|
- mostrad información de envíos y dispositivos en ui
|
||||||
|
|
|
@ -91,39 +91,9 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer):
|
||||||
volumeBox->setSpacing(0);
|
volumeBox->setSpacing(0);
|
||||||
volumeBox->setContentsMargins(0, 0, 0, 0);
|
volumeBox->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->addLayout(volumeBox);
|
layout->addLayout(volumeBox);
|
||||||
QHBoxLayout *labelsBox = new QHBoxLayout;
|
m_level = new QLabel();
|
||||||
m_level = new QLabel("-inf");
|
m_level->setText("0");
|
||||||
m_level->setStyleSheet("border: 1px solid #5a4855;"
|
layout->addWidget(m_level);
|
||||||
"margin: 0px;"
|
|
||||||
"background-color: #180014;"
|
|
||||||
"color: white;"
|
|
||||||
"width:70px;"
|
|
||||||
"text-align: center;"
|
|
||||||
);
|
|
||||||
m_level->setMinimumWidth(70);
|
|
||||||
m_level->setAlignment(Qt::AlignHCenter);
|
|
||||||
labelsBox->addWidget(m_level);
|
|
||||||
m_bus1Label = new QLabel("dummy");
|
|
||||||
m_bus1Label->setMinimumWidth(80);
|
|
||||||
m_bus1Label->setStyleSheet("border: 1px solid #5a4855;"
|
|
||||||
"margin: 0px;"
|
|
||||||
"background-color: #383034;"
|
|
||||||
"width:70px;"
|
|
||||||
);
|
|
||||||
m_bus1Label->setAlignment(Qt::AlignHCenter);
|
|
||||||
labelsBox->addWidget(m_bus1Label);
|
|
||||||
m_bus2Label = new QLabel("dummy");
|
|
||||||
m_bus2Label->setMinimumWidth(80);
|
|
||||||
m_bus2Label->setStyleSheet("border: 1px solid #5a4855;"
|
|
||||||
"margin: 0px;"
|
|
||||||
"background-color: #383034;"
|
|
||||||
"width: 70px;"
|
|
||||||
);
|
|
||||||
m_bus2Label->setAlignment(Qt::AlignHCenter);
|
|
||||||
labelsBox->addWidget(m_bus2Label);
|
|
||||||
labelsBox->setSpacing(0);
|
|
||||||
labelsBox->setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->addLayout(labelsBox);
|
|
||||||
layout->setAlignment(Qt::AlignHCenter);
|
layout->setAlignment(Qt::AlignHCenter);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
layout->setContentsMargins(1, 1, 1, 1);
|
layout->setContentsMargins(1, 1, 1, 1);
|
||||||
|
@ -198,7 +168,6 @@ void AudioLayerWidget::openMediaDialog()
|
||||||
fileNames = dialog.selectedFiles();
|
fileNames = dialog.selectedFiles();
|
||||||
emit uiLoadMedia(m_layer, fileNames.at(0));
|
emit uiLoadMedia(m_layer, fileNames.at(0));
|
||||||
this->setMediaFile(fileNames.at(0));
|
this->setMediaFile(fileNames.at(0));
|
||||||
this->setPlaybackStatus(Status::Stopped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// from DMX signals
|
// from DMX signals
|
||||||
|
@ -268,40 +237,27 @@ void AudioLayerWidget::setCurrentTime(float progress)
|
||||||
|
|
||||||
void AudioLayerWidget::setFilterParam(int channel, int value)
|
void AudioLayerWidget::setFilterParam(int channel, int value)
|
||||||
{
|
{
|
||||||
if (channel <= FILTER_BANK_GAIN - HP_FREQ){
|
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) {
|
} else if (channel == SEND1 - HP_FREQ) {
|
||||||
m_bus1->blockSignals(true);
|
|
||||||
m_bus1->setValue((value * 256) + 255);
|
|
||||||
m_bus1->blockSignals(false);
|
m_bus1->blockSignals(false);
|
||||||
|
m_bus1->setValue((value * 256) + 255);
|
||||||
|
m_bus1->blockSignals(true);
|
||||||
} else if (channel == SEND2 - HP_FREQ) {
|
} else if (channel == SEND2 - HP_FREQ) {
|
||||||
m_bus2->blockSignals(true);
|
|
||||||
m_bus2->setValue(value * 256 + 255);
|
|
||||||
m_bus2->blockSignals(false);
|
m_bus2->blockSignals(false);
|
||||||
|
m_bus2->setValue(value * 256 + 255);
|
||||||
|
m_bus2->blockSignals(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::setLevel(float db)
|
void AudioLayerWidget::setLevel(float db)
|
||||||
{
|
{
|
||||||
m_level->blockSignals(true);
|
m_level->blockSignals(true);
|
||||||
if (db > -150)
|
if (db > -200)
|
||||||
m_level->setText(QString::number(db));
|
m_level->setText(QString::number(db));
|
||||||
else
|
else
|
||||||
m_level->setText("-inf");
|
m_level->setText("-inf");
|
||||||
m_level->blockSignals(false);
|
m_level->blockSignals(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioLayerWidget::setBusName(uint bus, char *name)
|
|
||||||
{
|
|
||||||
if (bus == 0) {
|
|
||||||
m_bus1Label->blockSignals(true);
|
|
||||||
m_bus1Label->setText(name);
|
|
||||||
m_bus1Label->blockSignals(false);
|
|
||||||
} else if (bus == 1) {
|
|
||||||
m_bus2Label->blockSignals(true);
|
|
||||||
m_bus2Label->setText(name);
|
|
||||||
m_bus2Label->blockSignals(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ public:
|
||||||
void setPitch(int pitch);
|
void setPitch(int pitch);
|
||||||
void setFilterParam(int channel, int value);
|
void setFilterParam(int channel, int value);
|
||||||
void setLevel(float db);
|
void setLevel(float db);
|
||||||
void setBusName(uint bus, char *name);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Status m_status;
|
Status m_status;
|
||||||
|
@ -38,6 +37,7 @@ private:
|
||||||
QPushButton *m_suspendResumeButton;
|
QPushButton *m_suspendResumeButton;
|
||||||
ClickableLabel *m_fileValue;
|
ClickableLabel *m_fileValue;
|
||||||
ClickableLabel * m_folderValue;
|
ClickableLabel * m_folderValue;
|
||||||
|
QLabel *m_level;
|
||||||
SliderGroup *m_volume;
|
SliderGroup *m_volume;
|
||||||
SliderGroup *m_pan;
|
SliderGroup *m_pan;
|
||||||
SliderGroup *m_pitch;
|
SliderGroup *m_pitch;
|
||||||
|
@ -47,9 +47,8 @@ private:
|
||||||
QTimeEdit *m_totalTimeValue;
|
QTimeEdit *m_totalTimeValue;
|
||||||
QProgressBar *m_progress;
|
QProgressBar *m_progress;
|
||||||
FilterBankWidget *m_filterBank;
|
FilterBankWidget *m_filterBank;
|
||||||
QLabel *m_level;
|
|
||||||
QLabel *m_bus1Label;
|
//public slots:
|
||||||
QLabel *m_bus2Label;
|
|
||||||
|
|
||||||
// From Ui
|
// From Ui
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
@ -123,12 +123,3 @@ void AudioWidget::levelChanged(int layer, float db)
|
||||||
m_layerUpdate[layer].level = db;
|
m_layerUpdate[layer].level = db;
|
||||||
m_layerUpdate[layer].updated = true;
|
m_layerUpdate[layer].updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioWidget::busNameChanged(uint bus, char* name)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < m_layers; i++) {
|
|
||||||
QLayoutItem *item = m_layout->itemAt(i);
|
|
||||||
AudioLayerWidget *alw = dynamic_cast<AudioLayerWidget *>(item->widget());
|
|
||||||
alw->setBusName(bus, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ public:
|
||||||
AudioWidget(QWidget *parent = nullptr);
|
AudioWidget(QWidget *parent = nullptr);
|
||||||
void filterParamChanged(int layer, int channel, int value);
|
void filterParamChanged(int layer, int channel, int value);
|
||||||
void levelChanged(int layer, float db);
|
void levelChanged(int layer, float db);
|
||||||
void busNameChanged(uint bus, char *name);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHBoxLayout *m_layout;
|
QHBoxLayout *m_layout;
|
||||||
|
|
|
@ -70,7 +70,8 @@ void libreMediaServerAudio::loadMedia(int layer, int folder, int file)
|
||||||
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
|
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
|
||||||
return;
|
return;
|
||||||
if (QFile::exists(mediaFile)){
|
if (QFile::exists(mediaFile)){
|
||||||
m_mae.loadMedia(layer, mediaFile.toLatin1().data());
|
m_mae.loadMedia(layer, mediaFile.toLatin1().data(),\
|
||||||
|
m_dmxSettings.at(layer).audioDevice);
|
||||||
m_currentMedia[layer] = mediaFile;
|
m_currentMedia[layer] = mediaFile;
|
||||||
#ifndef NOGUI
|
#ifndef NOGUI
|
||||||
if (m_ui)
|
if (m_ui)
|
||||||
|
@ -134,7 +135,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else if (channel >= HP_FREQ) {
|
} else if (channel >= HP_FREQ) {
|
||||||
m_mae.filterParamChanged(layer, channel, value);
|
m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value);
|
||||||
#ifndef NOGUI
|
#ifndef NOGUI
|
||||||
if (m_ui) {
|
if (m_ui) {
|
||||||
m_lmsUi->m_aw->filterParamChanged(layer, channel, value);
|
m_lmsUi->m_aw->filterParamChanged(layer, channel, value);
|
||||||
|
@ -228,10 +229,6 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi)
|
||||||
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
|
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
|
||||||
m_refreshUi->start(UI_REFRESH_TIME);
|
m_refreshUi->start(UI_REFRESH_TIME);
|
||||||
m_ola->start(QThread::TimeCriticalPriority );
|
m_ola->start(QThread::TimeCriticalPriority );
|
||||||
for (uint i = 0; i < m_settings->getAudioDeviceQty(); i++) {
|
|
||||||
char *name = m_mae.getDeviceName(i);
|
|
||||||
m_lmsUi->m_aw->busNameChanged(i, name);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// From Ui widgets
|
// From Ui widgets
|
||||||
|
@ -251,10 +248,10 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
|
||||||
m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value);
|
m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value);
|
||||||
break;
|
break;
|
||||||
case Slider::Bus1:
|
case Slider::Bus1:
|
||||||
m_mae.filterParamChanged(layer, SEND1, value / 255.0f);
|
m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND1, value / 255);
|
||||||
break;
|
break;
|
||||||
case Slider::Bus2:
|
case Slider::Bus2:
|
||||||
m_mae.filterParamChanged(layer, SEND2, value / 255.0f);
|
m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND2, value / 255);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +274,7 @@ void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile)
|
||||||
|
|
||||||
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
|
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
|
||||||
return;
|
return;
|
||||||
result = m_mae.loadMedia(layer, mediaFile.toLatin1().data());
|
result = m_mae.loadMedia(layer, mediaFile.toLatin1().data(), m_dmxSettings[layer].audioDevice);
|
||||||
if (result == MA_SUCCESS) {
|
if (result == MA_SUCCESS) {
|
||||||
m_currentMedia[layer] = mediaFile;
|
m_currentMedia[layer] = mediaFile;
|
||||||
m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer));
|
m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer));
|
||||||
|
|
|
@ -38,6 +38,8 @@ static ma_node_vtable g_ma_writer_node_vtable =
|
||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
0
|
0
|
||||||
|
// MA_NODE_FLAG_CONTINUOUS_PROCESSING
|
||||||
|
// MA_NODE_FLAG_SILENT_OUTPUT
|
||||||
};
|
};
|
||||||
|
|
||||||
MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode)
|
MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode)
|
||||||
|
@ -176,7 +178,7 @@ void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource)
|
||||||
* vumeter
|
* vumeter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 format, ma_uint32 sampleRate)
|
MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 sampleRate)
|
||||||
{
|
{
|
||||||
ma_vumeter_node_config config;
|
ma_vumeter_node_config config;
|
||||||
|
|
||||||
|
@ -184,7 +186,6 @@ MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma
|
||||||
config.nodeConfig = ma_node_config_init();
|
config.nodeConfig = ma_node_config_init();
|
||||||
config.channels = channels;
|
config.channels = channels;
|
||||||
config.sampleRate = sampleRate;
|
config.sampleRate = sampleRate;
|
||||||
config.format = format;
|
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +201,7 @@ static void ma_vumeter_node_process_pcm_frames(ma_node* pNode, const float** ppF
|
||||||
float input = fabsf(ppFramesIn[0][i]);
|
float input = fabsf(ppFramesIn[0][i]);
|
||||||
pVumeterNode->level += pVumeterNode->alpha * (input - pVumeterNode->level);
|
pVumeterNode->level += pVumeterNode->alpha * (input - pVumeterNode->level);
|
||||||
}
|
}
|
||||||
ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, pVumeterNode->format, pVumeterNode->channels);
|
ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pVumeterNode->channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ma_node_vtable g_ma_vumeter_node_vtable =
|
static ma_node_vtable g_ma_vumeter_node_vtable =
|
||||||
|
@ -237,9 +238,8 @@ MA_API ma_result ma_vumeter_node_init(ma_node_graph* pNodeGraph, const ma_vumete
|
||||||
}
|
}
|
||||||
pVumeterNode->sampleRate = pConfig->sampleRate;
|
pVumeterNode->sampleRate = pConfig->sampleRate;
|
||||||
pVumeterNode->channels = pConfig->channels;
|
pVumeterNode->channels = pConfig->channels;
|
||||||
pVumeterNode->format = pConfig->format;
|
|
||||||
pVumeterNode->level = 0;
|
pVumeterNode->level = 0;
|
||||||
pVumeterNode->TC = 0.250f;
|
pVumeterNode->TC = 10000.0f;
|
||||||
pVumeterNode->alpha = 1.0 - expf( (-2.0 * M_PI) / (pVumeterNode->TC * pConfig->sampleRate));
|
pVumeterNode->alpha = 1.0 - expf( (-2.0 * M_PI) / (pVumeterNode->TC * pConfig->sampleRate));
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,17 +59,15 @@ typedef struct
|
||||||
ma_node_config nodeConfig;
|
ma_node_config nodeConfig;
|
||||||
ma_uint32 channels;
|
ma_uint32 channels;
|
||||||
ma_uint32 sampleRate;
|
ma_uint32 sampleRate;
|
||||||
ma_uint32 format;
|
|
||||||
} ma_vumeter_node_config;
|
} ma_vumeter_node_config;
|
||||||
|
|
||||||
MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 format, ma_uint32 sampleRate);
|
MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 sampleRate);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ma_node_base baseNode;
|
ma_node_base baseNode;
|
||||||
ma_uint32 channels;
|
ma_uint32 channels;
|
||||||
ma_uint32 sampleRate;
|
ma_uint32 sampleRate;
|
||||||
ma_uint32 format;
|
|
||||||
float level;
|
float level;
|
||||||
float TC;
|
float TC;
|
||||||
float alpha;
|
float alpha;
|
||||||
|
|
|
@ -132,7 +132,7 @@ 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;
|
||||||
}
|
}
|
||||||
ma_vumeter_node_config vuc = ma_vumeter_node_config_init(CHANNELS, FORMAT, SAMPLE_RATE);
|
ma_vumeter_node_config vuc = ma_vumeter_node_config_init(CHANNELS, FORMAT);
|
||||||
ma_vumeter_node_init(ng, &vuc, NULL, &fb->vumeter);
|
ma_vumeter_node_init(ng, &vuc, NULL, &fb->vumeter);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
cout << "ERROR " << result << ": Failed to init vumeter node." << endl;
|
cout << "ERROR " << result << ": Failed to init vumeter node." << endl;
|
||||||
|
@ -278,7 +278,7 @@ ma_result MiniAudioEngine::startDevices()
|
||||||
deviceConfig.dataCallback = audioDataCallback;
|
deviceConfig.dataCallback = audioDataCallback;
|
||||||
engineConfig = ma_engine_config_init();
|
engineConfig = ma_engine_config_init();
|
||||||
engineConfig.pResourceManager = &m_mae.resourceManager;
|
engineConfig.pResourceManager = &m_mae.resourceManager;
|
||||||
engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 20;
|
engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 25;
|
||||||
engineConfig.noAutoStart = MA_TRUE;
|
engineConfig.noAutoStart = MA_TRUE;
|
||||||
|
|
||||||
for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) {
|
for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) {
|
||||||
|
@ -340,34 +340,25 @@ ma_result MiniAudioEngine::getAllAudioDevices()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* MiniAudioEngine::getDeviceName(uint id)
|
ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice)
|
||||||
{
|
|
||||||
return m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[id]].name;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ma_result MiniAudioEngine::loadMedia(int layer, char *file)
|
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
|
|
||||||
if (m_mae.mediaLoaded[layer] == true)
|
if (m_mae.mediaLoaded[layer] == true)
|
||||||
{
|
{
|
||||||
ma_sound_set_volume(&m_mae.sounds[layer], 0.0f);
|
|
||||||
ma_sound_stop(&m_mae.sounds[layer]);
|
|
||||||
ma_sound_uninit(&m_mae.sounds[layer]);
|
ma_sound_uninit(&m_mae.sounds[layer]);
|
||||||
m_mae.mediaLoaded[layer] = false;
|
m_mae.mediaLoaded[layer] = false;
|
||||||
}
|
}
|
||||||
ma_sound_config soundConfig = ma_sound_config_init();
|
result = ma_sound_init_from_file(&m_mae.engines[0], file, \
|
||||||
soundConfig = ma_sound_config_init();
|
MA_SOUND_FLAG_NO_SPATIALIZATION \
|
||||||
soundConfig.pFilePath = file;
|
, NULL, NULL, &m_mae.sounds[layer]);
|
||||||
soundConfig.pInitialAttachment = &m_mae.filters[layer].input;
|
|
||||||
soundConfig.initialAttachmentInputBusIndex = 0;
|
|
||||||
soundConfig.channelsIn = 0;
|
|
||||||
soundConfig.channelsOut = CHANNELS;
|
|
||||||
soundConfig.flags = MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT | MA_SOUND_FLAG_STREAM; //| MA_SOUND_FLAG_NO_PITCH
|
|
||||||
result = ma_sound_init_ex(&m_mae.engines[0], &soundConfig, &m_mae.sounds[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;
|
||||||
|
}
|
||||||
|
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_mae.mediaLoaded[layer] = true;
|
m_mae.mediaLoaded[layer] = true;
|
||||||
|
@ -438,7 +429,7 @@ void MiniAudioEngine::volChanged(int layer, int vol)
|
||||||
db = 0;
|
db = 0;
|
||||||
} else
|
} else
|
||||||
db = ma_volume_db_to_linear(db);
|
db = ma_volume_db_to_linear(db);
|
||||||
ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME);
|
ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME);
|
||||||
m_mae.currentStatus[layer].vol = vol;
|
m_mae.currentStatus[layer].vol = vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,13 +479,12 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status)
|
||||||
ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0);
|
ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0);
|
||||||
ma_sound_set_looping(&m_mae.sounds[layer], loop);
|
ma_sound_set_looping(&m_mae.sounds[layer], loop);
|
||||||
result = ma_sound_start(&m_mae.sounds[layer]);
|
result = ma_sound_start(&m_mae.sounds[layer]);
|
||||||
//this->volChanged(layer, m_mae.currentStatus[layer].vol);
|
if (m_mae.currentStatus[layer].cursor != 0) {
|
||||||
float db = (m_mae.currentStatus[layer].vol / 771.0f) - 85.0f;
|
usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line?
|
||||||
if (db <= -85.0f) {
|
}
|
||||||
db = 0;
|
this->volChanged(layer, m_mae.currentStatus[layer].vol);
|
||||||
} else
|
default:
|
||||||
db = ma_volume_db_to_linear(db);
|
break;
|
||||||
ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, 0);
|
|
||||||
}
|
}
|
||||||
if (result == MA_SUCCESS)
|
if (result == MA_SUCCESS)
|
||||||
m_mae.currentStatus[layer].status = status;
|
m_mae.currentStatus[layer].status = status;
|
||||||
|
@ -510,7 +500,7 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor)
|
||||||
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_mae.sounds[layer], &end);
|
||||||
if (result != MA_SUCCESS) { return result; }
|
if (result != MA_SUCCESS) { return result; }
|
||||||
start = (cursor * end) / 65535;
|
start = (cursor * end) / 65025;
|
||||||
Status oldStatus = m_mae.currentStatus[layer].status;
|
Status oldStatus = m_mae.currentStatus[layer].status;
|
||||||
result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], 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?
|
//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?
|
||||||
|
@ -535,14 +525,14 @@ void MiniAudioEngine::refreshValues(int layer)
|
||||||
{
|
{
|
||||||
this->seekToCursor(layer, m_mae.currentStatus[layer].cursor);
|
this->seekToCursor(layer, m_mae.currentStatus[layer].cursor);
|
||||||
this->panChanged(layer, m_mae.currentStatus[layer].pan);
|
this->panChanged(layer, m_mae.currentStatus[layer].pan);
|
||||||
this->pitchChanged(layer, m_mae.currentStatus[layer].pitch);
|
|
||||||
ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, 0, 0.0f);
|
|
||||||
this->playbackChanged(layer, m_mae.currentStatus[layer].status);
|
|
||||||
this->volChanged(layer, m_mae.currentStatus[layer].vol);
|
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 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_mae.filters[layer];
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ typedef struct
|
||||||
ma_resource_manager resourceManager;
|
ma_resource_manager resourceManager;
|
||||||
ma_context context;
|
ma_context context;
|
||||||
ma_device_info* pPlaybackDeviceInfos;
|
ma_device_info* pPlaybackDeviceInfos;
|
||||||
ma_device_info pSelectedPlaybackDeviceInfos[MAX_AUDIODEVICES];
|
|
||||||
ma_uint32 playbackDeviceCount;
|
ma_uint32 playbackDeviceCount;
|
||||||
ma_uint32 devicesSelected;
|
ma_uint32 devicesSelected;
|
||||||
ma_bool8 mediaLoaded[MAX_LAYERS];
|
ma_bool8 mediaLoaded[MAX_LAYERS];
|
||||||
|
@ -59,13 +58,13 @@ class MiniAudioEngine
|
||||||
friend class libreMediaServerAudio;
|
friend class libreMediaServerAudio;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
MiniAudioEngine();
|
MiniAudioEngine();
|
||||||
void stopEngine();
|
void stopEngine();
|
||||||
bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty);
|
bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty);
|
||||||
ma_result loadMedia(int layer, char *media);
|
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ma_result loadMedia(int layer, char *media, uint audioDevice);
|
||||||
void volChanged(int layer, int vol);
|
void volChanged(int layer, int 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);
|
||||||
|
@ -79,13 +78,12 @@ protected:
|
||||||
return ma_sound_get_volume(&m_mae.sounds[layer]);
|
return ma_sound_get_volume(&m_mae.sounds[layer]);
|
||||||
};
|
};
|
||||||
inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; }
|
inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; }
|
||||||
ma_result filterParamChanged(int layer, int channel, int value);
|
ma_result filterParamChanged(int layer, int audioDevice, int channel, int value);
|
||||||
bool setBypass(int audioDevice, int layer, bool bypass);
|
bool setBypass(int audioDevice, int layer, bool bypass);
|
||||||
inline float getLevel(int layer) {
|
inline float getLevel(int layer) {
|
||||||
float level = ma_vumeter_node_get_level(&m_mae.filters[layer].vumeter);
|
float level = ma_vumeter_node_get_level(&m_mae.filters[layer].vumeter);
|
||||||
return ma_volume_linear_to_db(level) - 4.0f;
|
return ma_volume_linear_to_db(level);
|
||||||
};
|
};
|
||||||
char* getDeviceName(uint id);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MAE m_mae;
|
MAE m_mae;
|
||||||
|
|
Loading…
Add table
Reference in a new issue