Antigona Release #1

Merged
snt merged 49 commits from filters into main 2024-05-26 12:42:53 +00:00
8 changed files with 390 additions and 90 deletions
Showing only changes of commit fc274179ad - Show all commits

View file

@ -8,9 +8,11 @@ HEADERS += src/libremediaserver-audio.h \
src/dmxwidget.h \
src/filterbankwidget.h \
src/libremediaserver-audio-gui.h \
src/ma_writer_node.h \
src/main.h \
src/miniaudio.h \
src/medialibrary.h \
src/miniaudio.h \
src/ma_writer_node.h \
src/miniaudioengine.h \
src/olathread.h \
src/audiolayerwidget.h \
@ -26,10 +28,11 @@ SOURCES += src/main.cpp \
src/dmxwidget.cpp \
src/filterbankwidget.cpp \
src/libremediaserver-audio-gui.cpp \
src/miniaudio.c \
src/libremediaserver-audio.cpp \
src/medialibrary.cpp \
src/miniaudio.c \
src/miniaudioengine.cpp \
src/ma_writer_node.c \
src/olathread.cpp \
src/audiolayerwidget.cpp \
src/audiowidget.cpp \

View file

@ -1,15 +1,18 @@
#ifndef DEFINES_H
#define DEFINES_H
#define VERSION "LibreMediaServerAudio v0.2.0 Antigona"
#define COPYRIGHT "(C) 2014-2024 Santi Noreña <lms@criptomart.net>"
#define LICENSE "GPL 3 Licensed. See LICENSE.txt."
#define DEFAULT_FILE "lms-audio.xlm"
#define MAX_LAYERS 4
#define MAX_AUDIODEVICES 8
#define UI_REFRESH_TIME 100
#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 VERSION "LibreMediaServerAudio v0.2.0 Antigona"
#define COPYRIGHT "(C) 2014-2024 Santi Noreña <lms@criptomart.net>"
#define LICENSE "GPL3 Licensed. See LICENSE.txt."
#define DEFAULT_FILE "lms-audio.xlm"
#define MAX_LAYERS 4
#define MAX_AUDIODEVICES 8
#define FORMAT ma_format_f32 /* Must always be f32. */
#define CHANNELS 2
#define SAMPLE_RATE 48000
#define UI_REFRESH_TIME 100
#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks
#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer
struct dmxSetting {
int address;
@ -18,7 +21,7 @@ struct dmxSetting {
int audioDevice;
};
enum class Status
enum Status
{
Stopped,
Paused,
@ -30,6 +33,15 @@ enum class Status
PlayingFolderRandom
};
enum Slider
{
Volume,
Pan,
Pitch,
Bypass
};
#ifdef __cplusplus
constexpr const char* statusToString(Status e) noexcept
{
switch (e)
@ -45,27 +57,6 @@ constexpr const char* statusToString(Status e) noexcept
default: return "--++--";
}
}
/*
static const char* StatusStr[] =
{
"Stop",
"Pause",
"Play One",
"Play One Loop",
"Iddle",
"Play Folder",
"Play Folder Loop",
"Play Folder Rand",
0x0
};*/
enum Slider
{
Volume,
Pan,
Pitch,
Bypass
};
#include <QString>
struct layerData {
@ -81,4 +72,5 @@ struct layerData {
unsigned int universe;
int device;
};
#endif // __cplusplus
#endif // DEFINES_H

View file

@ -23,9 +23,10 @@
#define HIGH_FREQ 19
#define HIGH_Q 20
#define HIGH_GAIN 21
#define SEND1 22
#define SEND2 23
#define LAYER_CHANNELS 24
#define FILTER_BANK_GAIN 22 // not implemented yet
#define SEND1 23
#define SEND2 24
#define LAYER_CHANNELS 25
constexpr const char* dmxChannelToString(int e) noexcept
{
@ -43,6 +44,7 @@ constexpr const char* dmxChannelToString(int e) noexcept
case HIGH_FREQ: return "High Cutoff Frec";
case HIGH_Q: return "High Slope";
case HIGH_GAIN: return "High Gain";
case FILTER_BANK_GAIN: return "Post Filters Gain";
default: return "++--++--++";
}
}

View file

@ -28,19 +28,9 @@ FilterBankWidget::FilterBankWidget(QWidget *parent)
master->addWidget(m_bypass);
m_bypass->setText("Bypass");
m_bypass->setStyleSheet("QCheckBox { border: 2px solid #2a0825;"
"text-align: left top;"
"margin: 0px;"
"background-color: #885074;"
"font-size: 7px;}"
"QCheckBox::indicator { subcontrol-position: right top;"
"width: 30px;"
"height: 30px;"
"background-color: gray;"
"border-radius: 15px;"
"border-style: solid;"
"border-width: 1px;"
"border-color: white white black black;"
);
"font-size: 7px;}");
connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int)));
master->addWidget(fb[0]);
layout->addLayout(master);

175
src/ma_writer_node.c Normal file
View file

@ -0,0 +1,175 @@
#include "ma_writer_node.h"
#include "miniaudio.c"
MA_API ma_writer_node_config ma_writer_node_config_init(ma_uint32 channels, ma_uint32 bufferSizeInFrames, ma_pcm_rb *rb)
{
ma_writer_node_config config;
MA_ZERO_OBJECT(&config);
config.nodeConfig = ma_node_config_init();
config.channels = channels;
config.bufferSizeInFrames = bufferSizeInFrames;
config.pBuffer = rb;
return config;
}
static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
{
ma_writer_node* pWriteNode = (ma_writer_node*)pNode;
MA_ASSERT(pWriteNode != NULL);
MA_ASSERT(ma_node_get_input_bus_count(&pWriteNode->baseNode) == 1);
if (*pFrameCountIn > 0) {
void *pWriteBuffer = NULL;
ma_pcm_rb_acquire_write(pWriteNode->pBuffer, pFrameCountIn, &pWriteBuffer);
if (pWriteBuffer != NULL) {
ma_copy_pcm_frames(pWriteBuffer, ppFramesIn[0], *pFrameCountIn, ma_format_f32, pWriteNode->channels);
ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn);
}
//ma_silence_pcm_frames(ppFramesOut[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels);
}
//*pFrameCountOut = 0;
ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels);
}
static ma_node_vtable g_ma_writer_node_vtable =
{
ma_writer_node_process_pcm_frames,
NULL,
1,
1,
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_result result;
ma_node_config baseConfig;
if (pWriteNode == NULL || pConfig == NULL || pConfig->pBuffer == NULL \
|| (pConfig->channels > MA_MAX_NODE_BUS_COUNT) ) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pWriteNode);
baseConfig = pConfig->nodeConfig;
baseConfig.vtable = &g_ma_writer_node_vtable;
baseConfig.pInputChannels = &pConfig->channels;
baseConfig.pOutputChannels = &pConfig->channels;
result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pWriteNode->baseNode);
if (result != MA_SUCCESS) {
return result;
}
pWriteNode->bufferSizeInFrames = pConfig->bufferSizeInFrames;
pWriteNode->pBuffer = pConfig->pBuffer;
pWriteNode->channels = pConfig->channels;
return MA_SUCCESS;
}
MA_API void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocation_callbacks* pAllocationCallbacks)
{
ma_node_uninit(&pWriteNode->baseNode, pAllocationCallbacks);
}
/*
* Data Source Ring Buffer
*/
ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_data_source_rb* ds = (ma_data_source_rb*)pDataSource;
ma_uint32 pcmFramesAvailableInRB = 0;
ma_uint32 pcmFramesProcessed = 0;
// lo mismo que en el callback, va el doble de rápido y con glitches.
while (pcmFramesProcessed < frameCount) {
pcmFramesAvailableInRB = ma_pcm_rb_available_read(ds->rb);
if (pcmFramesAvailableInRB == 0) {
break;
}
ma_uint32 framesToRead = frameCount - pcmFramesProcessed;
if (framesToRead > pcmFramesAvailableInRB) {
framesToRead = pcmFramesAvailableInRB;
}
void* pReadBuffer = NULL;
ma_pcm_rb_acquire_read(ds->rb, &framesToRead, &pReadBuffer);
if (pReadBuffer != NULL) {
ma_copy_pcm_frames(pFramesOut, pReadBuffer, framesToRead, ma_format_f32, 2);
ma_pcm_rb_commit_read(ds->rb, framesToRead);
pcmFramesProcessed += framesToRead;
}
else {
break;
}
}
*pFramesRead += pcmFramesProcessed;
return MA_SUCCESS;
}
ma_result ma_data_source_rb_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
(void)pDataSource;
(void)frameIndex;
return MA_NOT_IMPLEMENTED;
}
ma_result ma_data_source_rb_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
(void)pDataSource;
*pFormat = ma_format_f32;
*pChannels = 2;
*pSampleRate = ma_standard_sample_rate_48000;
return MA_SUCCESS;
}
ma_result ma_data_source_rb_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
(void)pDataSource;
*pCursor = 0;
return MA_NOT_IMPLEMENTED;
}
ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
(void)pDataSource;
*pLength = 0;
return MA_NOT_IMPLEMENTED;
}
ma_data_source_vtable g_ma_data_source_rb_vtable =
{
ma_data_source_rb_read,
ma_data_source_rb_seek,
ma_data_source_rb_get_data_format,
ma_data_source_rb_get_cursor,
ma_data_source_rb_get_length
};
ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer)
{
ma_result result;
ma_data_source_config baseConfig;
baseConfig = ma_data_source_config_init();
baseConfig.vtable = &g_ma_data_source_rb_vtable;
result = ma_data_source_init(&baseConfig, &pMyDataSource->base);
if (result != MA_SUCCESS) {
return result;
}
pMyDataSource->rb = ringBuffer;
return MA_SUCCESS;
}
void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource)
{
ma_data_source_uninit(&pMyDataSource->base);
}

52
src/ma_writer_node.h Normal file
View file

@ -0,0 +1,52 @@
/* Include ma_writer_node.h after miniaudio.h */
#ifndef ma_writer_node_h
#define ma_writer_node_h
#ifdef __cplusplus
extern "C" {
#endif
#include "miniaudio.h"
typedef struct
{
ma_node_config nodeConfig;
ma_uint32 channels;
ma_uint32 bufferSizeInFrames;
ma_pcm_rb *pBuffer;
} ma_writer_node_config;
MA_API ma_writer_node_config ma_writer_node_config_init(ma_uint32 channels, ma_uint32 bufferSizeInFrames, ma_pcm_rb *rb);
typedef struct
{
ma_node_base baseNode;
ma_uint32 bufferSizeInFrames;
ma_pcm_rb *pBuffer;
ma_uint32 channels;
} ma_writer_node;
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 void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocation_callbacks* pAllocationCallbacks);
/**
* data source ring buffer
*/
typedef struct
{
ma_data_source_base base;
ma_pcm_rb *rb;
} ma_data_source_rb;
ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
ma_result ma_data_source_rb_seek(ma_data_source* pDataSource, ma_uint64 frameIndex);
ma_result ma_data_source_rb_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
ma_result ma_data_source_rb_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor);
ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* pLength);
ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer);
void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource);
#ifdef __cplusplus
}
#endif
#endif /* ma_writer_node_h */

View file

@ -4,16 +4,48 @@
#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)
{
(void)pInput;
ma_result result;
result = ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": error audio callback.";
}
(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()
@ -23,6 +55,7 @@ void MiniAudioEngine::stopEngine()
}
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);
@ -30,6 +63,8 @@ void MiniAudioEngine::stopEngine()
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]);
}
@ -60,56 +95,55 @@ bool MiniAudioEngine::startEngine(uint layers)
ma_result MiniAudioEngine::createFilterBank(int id, 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];
filterBank *fb = &m_filterBank[id][layer];
ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS);
result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize input node." << endl;
cout << "ERROR " << result << ": Failed to init input node." << endl;
return result;
}
fb->hpfConfig = ma_hpf_node_config_init(CHANNELS, SAMPLE_RATE, 16, FILTER_ORDER);
result = ma_hpf_node_init(ng, &fb->hpfConfig, NULL, &fb->hpf);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize high pass filter node." << endl;
cout << "ERROR " << result << ": Failed to init high pass filter node." << endl;
return result;
}
fb->loshelfConfig = ma_loshelf_node_config_init(CHANNELS, SAMPLE_RATE, 0.0f, 1.0f, 30);
result = ma_loshelf_node_init(ng, &fb->loshelfConfig, NULL, &fb->loshelf);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize low pass filter node." << endl;
cout << "ERROR " << result << ": Failed to init low pass filter node." << endl;
return result;
}
fb->mLowConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 4.0, 200); // double gainDB, double q, double frequency);
result = ma_peak_node_init(ng, &fb->mLowConfig, NULL, &fb->mLow);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize peak low filter node." << endl;
cout << "ERROR " << result << ": Failed to init peak low filter node." << endl;
return result;
}
fb->mHighConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 0.0, 600); // double gainDB, double q, double frequency);
result = ma_peak_node_init(ng, &fb->mHighConfig, NULL, &fb->mHigh);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize peak high filter node." << endl;
cout << "ERROR " << result << ": Failed to init peak high filter node." << endl;
return result;
}
fb->hishelfConfig = ma_hishelf_node_config_init(CHANNELS, SAMPLE_RATE, 0.0f, 1.0f, 20000);
result = ma_hishelf_node_init(ng, &fb->hishelfConfig, NULL, &fb->hishelf);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize hi shelf filter node." << endl;
cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl;
return result;
}
result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to initialize output node." << endl;
cout << "ERROR " << result << ": Failed to init output node." << endl;
return result;
}
@ -120,7 +154,7 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer)
}
result = ma_node_attach_output_bus(&fb->input, 1, &fb->output, 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach high pass pass filter node." << endl;
cout << "ERROR " << result << ": Failed to attach bypass connection." << endl;
return result;
}
ma_node_set_output_bus_volume(&fb->input, 1, 0.0f);
@ -149,10 +183,17 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer)
cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl;
return result;
}
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;
return result;
if (id == 0) {
//result = ma_node_attach_output_bus(&fb->output, 1, endpoint, 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output node to engine." << endl;
return result;
}
result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl;
return result;
}
}
return result;
}
@ -161,19 +202,31 @@ ma_result MiniAudioEngine::setNodeGraph(int id) {
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 / 10; // 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;
}
}
while (result == MA_SUCCESS && i < m_layersQty) {
result = this->createFilterBank(id, i);
i++;
}
//ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]);
//ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]);
for (uint i = 0; i < m_layersQty; i++) {
result = ma_node_attach_output_bus(&m_filterBank[0][i].output, 0, &m_filterBank[1][i].output, 0);
if (result != MA_SUCCESS) {
cout << "ERROR " << result << ": Failed to attach aux send." << endl;
//return result;
}
}
return (result);
}
@ -185,12 +238,19 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
m_devicesSelected = nb;
for (uint internalId = 0; internalId < nb; internalId++) {
deviceConfig = ma_device_config_init(ma_device_type_playback);
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 = 0;
deviceConfig.playback.channels = CHANNELS;
deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate;
deviceConfig.dataCallback = audioDataCallback;
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]);
if (result != MA_SUCCESS) {
@ -200,6 +260,7 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
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]);
if (result != MA_SUCCESS) {
@ -218,6 +279,23 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb)
}
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;
}
@ -264,12 +342,8 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice)
{
ma_result result;
// ToDo: ver si s puede attach dos dispositivos a la vez. si no:
// - enchufar a un splitter al sonido y attach cada uno de los lados.
// - iniciar un sonido por cada capa, copiar la capa en otro dispositivo
// - splitter al final de filterBank, esas señales se mezclan en un nodo mudo
// y se escribe la mezcla en un buffer. Mezclar el buffer en disco con el
// del otro device en el audio callback .
// - writer node y source con el buffer escrito en el otro device
if (m_mediaLoaded[layer] == true)
{
ma_sound_uninit(&m_currentSound[layer]);
@ -284,7 +358,7 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice)
}
result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].input, 0);
if (result != MA_SUCCESS) {
cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl;
cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl;
//return result;
}
m_mediaLoaded[layer] = true;
@ -352,7 +426,7 @@ void MiniAudioEngine::volChanged(int layer, float vol)
return;
if (vol >= 1)
vol = 0.99f;
ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, vol, FADE_TIME);
ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, pow(vol, 3), FADE_TIME);
m_currentLayerValues[layer].vol = vol;
}

View file

@ -1,21 +1,19 @@
#ifndef MINIAUDIOENGINE_H
#define MINIAUDIOENGINE_H
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS 1
#define MA_ENABLE_JACK 1
#define MA_NO_GENERATION 1
#define MA_DEBUG_OUTPUT 1
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
#define MA_ENABLE_JACK
#define MA_NO_GENERATION
#define MA_DEBUG_OUTPUT
#define MA_DISABLE_PULSEAUDIO
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#include "defines.h" // MAX_LAYERS
#include "ma_writer_node.h"
#include <bits/stdc++.h>
using namespace std;
#include "defines.h"
/* Data Format */
#define FORMAT ma_format_f32 /* Must always be f32. */
#define CHANNELS 2
#define SAMPLE_RATE 48000
typedef struct
{
@ -31,12 +29,23 @@ 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;
class MiniAudioEngine
{
friend class libreMediaServerAudio;
static ma_pcm_rb *rb;
public:
MiniAudioEngine();
@ -44,6 +53,7 @@ public:
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 audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
bool setBypass(int audioDevice, int layer, bool bypass);
protected:
@ -76,6 +86,8 @@ private:
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 getAllAudioDevices();
ma_result startContext();