Skip to content

Commit

Permalink
rewrite buffers using interleaved format, fix distortion on AAC with …
Browse files Browse the repository at this point in the history
…7 channels
  • Loading branch information
ujifgc committed Jun 6, 2022
1 parent 36cc470 commit 3acfe2c
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 76 deletions.
Binary file modified Builds/VisualStudio2019/resources.aps
Binary file not shown.
8 changes: 4 additions & 4 deletions Builds/VisualStudio2019/resources.rc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//

IDR_VERSION VERSIONINFO
FILEVERSION 2022,5,4,1
PRODUCTVERSION 2022,5,4,1
FILEVERSION 2022,6,6,1
PRODUCTVERSION 2022,6,6,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -32,12 +32,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Igor Bochkariov"
VALUE "FileDescription", "Multi Channel Audio Capture"
VALUE "FileVersion", "2022.5.4.1"
VALUE "FileVersion", "2022.6.6.1"
VALUE "InternalName", "mcac.exe"
VALUE "LegalCopyright", "Copyright (C) 2022"
VALUE "OriginalFilename", "mcac.exe"
VALUE "ProductName", "Multi Channel Audio Capture"
VALUE "ProductVersion", "2022.5.4.1"
VALUE "ProductVersion", "2022.6.6.1"
END
END
BLOCK "VarFileInfo"
Expand Down
63 changes: 14 additions & 49 deletions Source/asio_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,10 @@ void AsioDevice::open() {
error = driver->createBuffers(buffer_infos, input_channels_number + output_channels_number, preferred_buffer_size, &callbacks[index]);
refuse(error);

for (int i = 0; i < input_channels_number; i += 1) {
sample_type_buffers[i] = (float*)calloc(preferred_buffer_size, sizeof(float));
for (int i = 0; i < MAX_INPUT_CHANNELS; i++) {
circlebuf_init(&input_buffers[i]);
input_buffer_pointers[i] = &input_buffers[i];
}
circlebuf_init(&input_buffer);
circlebuf_init(&interleaved_buffer);
driver_buffers_allocated = true;

initialize_latencies();
Expand Down Expand Up @@ -197,17 +196,7 @@ void AsioDevice::close() {

if (driver_buffers_allocated) {
driver->disposeBuffers();

for (int i = 0; i < input_channels_number; i += 1) {
if (sample_type_buffers[i]) {
free(sample_type_buffers[i]);
sample_type_buffers[i] = NULL;
}
}

circlebuf_free(&input_buffer);
circlebuf_free(&interleaved_buffer);

for (int i = 0; i < MAX_INPUT_CHANNELS; i++) circlebuf_free(&input_buffers[i]);
driver_buffers_allocated = false;
}

Expand Down Expand Up @@ -291,7 +280,7 @@ DWORD WINAPI AsioDevice::CaptureThread(void* data) {
int wait_result = WaitForMultipleObjects(2, signals, false, INFINITE);
if (wait_result == WAIT_OBJECT_0) {
EnterCriticalSection(&device->buffer_section);
if (writer) writer->write_packet(&device->input_buffer);
if (writer) writer->write_packet(device->input_buffer_pointers);
LeaveCriticalSection(&device->buffer_section);
}
else if (wait_result == WAIT_OBJECT_0 + 1) {
Expand Down Expand Up @@ -394,58 +383,34 @@ ASIOTime* AsioDevice::buffer_switch_time_info(int device_index, ASIOTime* timeIn
UNREFERENCED_PARAMETER(processNow);
}

static inline void* fill_interleaved_buffer(size_t channels, size_t samples, float** fdata, struct circlebuf* interleaved_buffer) {
circlebuf_upsize(interleaved_buffer, channels * samples * BYTES_PER_SAMPLE);
float* buffer = (float*)circlebuf_data(interleaved_buffer, 0);
extern float last_buffer_magnitude[MAX_INPUT_CHANNELS];

for (size_t c = 0; c < channels; c++) {
if (fdata[c]) {
float sum_of_squares = 0.0f;
for (size_t i = 0; i < samples; i++) {
float sample = buffer[i * channels + c] = fdata[c][i];
sum_of_squares += sample * sample;
}
last_buffer_magnitude[c] = sqrtf(sum_of_squares / samples);
}
else {
for (size_t i = 0; i < samples; i++) {
buffer[i * channels + c] = 0.0f;
}
last_buffer_magnitude[c] = 0.0f;
}
}
for (size_t c = channels; c < MAX_INPUT_CHANNELS; c++) {
last_buffer_magnitude[c] = 0.0f;
}

return buffer;
}

static ULONGLONG last_time = 0;

void AsioDevice::push_received_buffers(int buffer_index) {
int skipped = 0;

for (int channel = 0; channel < input_channels_number; channel += 1) {
if (active_channels[channel]) {
size_t data_size = input_buffers[channel - skipped].size;
circlebuf_upsize(&input_buffers[channel - skipped], data_size + (size_t)preferred_buffer_size * BYTES_PER_SAMPLE);
if (sample_type == ASIOSTInt32LSB) {
convertInt32ToFloat((const char*)buffer_infos[channel].buffers[buffer_index], sample_type_buffers[channel - skipped], preferred_buffer_size);
convertInt32ToFloat((const char*)buffer_infos[channel].buffers[buffer_index], (float*)circlebuf_data(&input_buffers[channel - skipped], data_size), preferred_buffer_size);
}
else {
memcpy(sample_type_buffers[channel - skipped], buffer_infos[channel].buffers[buffer_index], preferred_buffer_size * BYTES_PER_SAMPLE);
memcpy(circlebuf_data(&input_buffers[channel - skipped], data_size), buffer_infos[channel].buffers[buffer_index], (size_t)preferred_buffer_size * BYTES_PER_SAMPLE);
}
}
else {
skipped += 1;
}
}

fill_interleaved_buffer(active_channels_count, preferred_buffer_size, sample_type_buffers, &interleaved_buffer);
circlebuf_push_back(&input_buffer, circlebuf_data(&interleaved_buffer, 0), active_channels_count * preferred_buffer_size * BYTES_PER_SAMPLE);

extern float last_buffer_magnitude[MAX_INPUT_CHANNELS];
extern float buffer_magnitude[MAX_INPUT_CHANNELS];

for (int channel = 0; channel < active_channels_count; channel++) {
last_buffer_magnitude[channel] = ((float*)circlebuf_data(&input_buffers[channel], 0))[0];
}

for (int channel = 0; channel < input_channels_number; channel += 1) {
if (buffer_magnitude[channel] < last_buffer_magnitude[channel]) {
buffer_magnitude[channel] = last_buffer_magnitude[channel];
Expand Down
6 changes: 2 additions & 4 deletions Source/asio_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ class AsioDevice {

int output_samples_per_10ms = 0;

float* sample_type_buffers[MAX_INPUT_CHANNELS] = { 0 };

struct circlebuf input_buffer = { 0 };
struct circlebuf interleaved_buffer = { 0 };
circlebuf input_buffers[MAX_INPUT_CHANNELS] = { 0 };
circlebuf *input_buffer_pointers[MAX_INPUT_CHANNELS] = { 0 };

WinHandle stop_signal, receive_signal;
WinHandle capture_thread;
Expand Down
34 changes: 18 additions & 16 deletions Source/writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ Writer::Writer(class AsioDevice *_device) {

core_audio_ready = load_core_audio();

circlebuf_init(&encode_buffer);
circlebuf_init(&output_buffer);
}

Writer::~Writer() {
uninit();

circlebuf_free(&encode_buffer);
circlebuf_free(&output_buffer);

DeleteCriticalSection(&file_section);
Expand Down Expand Up @@ -53,8 +51,8 @@ void Writer::init(double _sample_rate) {
in.mSampleRate = sample_rate;
in.mChannelsPerFrame = channels;
in.mFormatID = kAudioFormatLinearPCM;
in.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsFloat;
in.mBytesPerFrame = channels * BYTES_PER_SAMPLE;
in.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved;
in.mBytesPerFrame = BYTES_PER_SAMPLE;
in.mFramesPerPacket = 1;
in.mBytesPerPacket = in.mFramesPerPacket * in.mBytesPerFrame;
in.mBitsPerChannel = BYTES_PER_SAMPLE * 8;
Expand Down Expand Up @@ -100,7 +98,7 @@ void Writer::init(double _sample_rate) {
kAudioChannelLayoutTag_AAC_4_0,
kAudioChannelLayoutTag_AAC_5_0,
kAudioChannelLayoutTag_AAC_6_0,
kAudioChannelLayoutTag_AAC_7_0, //distortion
kAudioChannelLayoutTag_AAC_7_0,
kAudioChannelLayoutTag_AAC_Octagonal,
};

Expand Down Expand Up @@ -220,38 +218,42 @@ OSStatus Writer::input_data_provider(AudioConverterRef inAudioConverter, UInt32*

UInt32 bytes_required = (*ioNumberDataPackets) * active_writer->bytes_per_input_packet;

if (active_writer->input_buffer->size < bytes_required) {
if (active_writer->input_buffers[0]->size < bytes_required) {
*ioNumberDataPackets = 0;
return MORE_DATA_REQUIRED;
}

circlebuf_upsize(&active_writer->encode_buffer, bytes_required);

ioData->mBuffers[0].mNumberChannels = active_writer->channels;
ioData->mBuffers[0].mDataByteSize = bytes_required;
ioData->mBuffers[0].mData = circlebuf_data(&active_writer->encode_buffer, 0);

circlebuf_pop_front(active_writer->input_buffer, ioData->mBuffers[0].mData, bytes_required);
for (int channel = 0; channel < active_writer->channels; channel++) {
ioData->mBuffers[channel].mNumberChannels = 1;
ioData->mBuffers[channel].mDataByteSize = bytes_required;
if (active_writer->input_buffers[channel]->size < bytes_required) {
circlebuf_push_back_zero(active_writer->input_buffers[channel], bytes_required);
}
ioData->mBuffers[channel].mData = circlebuf_data(active_writer->input_buffers[channel], 0);
circlebuf_pop_front(active_writer->input_buffers[channel], ioData->mBuffers[channel].mData, bytes_required);
}

return 0;

UNUSED_PARAMETER(inAudioConverter);
UNUSED_PARAMETER(outDataPacketDescription);
}

void Writer::write_packet(circlebuf* _input_buffer) {
void Writer::write_packet(circlebuf **_input_buffers) {
if (!core_audio_ready) {
message = "MCAC: AAC library not available";
PostMessage(message_window, WM_USER_WRITER_ERROR, 0, 0);
stop = true;
}

if (stop) {
circlebuf_pop_front(_input_buffer, nullptr, _input_buffer->size);
for (int i = 0; i < MAX_INPUT_CHANNELS; i++) {
circlebuf_pop_front(_input_buffers[i], nullptr, _input_buffers[i]->size);
}
return;
}

input_buffer = _input_buffer;
input_buffers = _input_buffers;

UInt32 packets_count = 1;
AudioBufferList output_buffers = { 0 };
Expand Down
5 changes: 2 additions & 3 deletions Source/writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ class Writer {
AudioConverterRef converter = nullptr;
unsigned bytes_per_input_packet = 0;
unsigned sample_rate = 0;
struct circlebuf encode_buffer = { 0 };
struct circlebuf output_buffer = { 0 };
circlebuf* input_buffer = nullptr;
circlebuf** input_buffers = nullptr;
FILE* file = nullptr;
bool stop = true;
CRITICAL_SECTION file_section;
Expand All @@ -63,5 +62,5 @@ class Writer {
bool open();
void close(bool report = true);
static OSStatus input_data_provider(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData);
void write_packet(circlebuf* _input_buffer);
void write_packet(circlebuf **_input_buffers);
};

0 comments on commit 3acfe2c

Please sign in to comment.