// ------------------------------------------------------------------------ // samplebuffer.cpp: Class representing a buffer of audio samples. // Copyright (C) 1999-2005,2009 Kai Vehmanen // // Attributes: // eca-style-version: 3 // // References: // - libsamplerate: // http://www.mega-nerd.com/SRC/ // - liboil: // http://liboil.freedesktop.org/ // http://library.gnome.org/devel/liboil/ // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ------------------------------------------------------------------------ #ifdef HAVE_CONFIG_H #include #endif #include #include #include /* ceil(), floor() */ #include /* memcpy */ #include /* not cstdlib we need e.g. posix_memalign() */ #include #include #include #ifdef ECA_COMPILE_SAMPLERATE #include #endif #ifdef ECA_USE_LIBOIL extern "C" { #include } #endif #include "eca-sample-conversion.h" #include "samplebuffer.h" #include "samplebuffer_impl.h" #include "eca-logger.h" /* Debug resampling operations */ // #define DEBUG_RESAMPLING #ifdef DEBUG_RESAMPLING #define DEBUG_RESAMPLING_STATEMENT(x) x #else #define DEBUG_RESAMPLING_STATEMENT(x) ((void)0) #endif #ifdef WORDS_BIGENDIAN static const bool is_system_littleendian = false; #else static const bool is_system_littleendian = true; #endif using namespace std; static void priv_alloc_sample_buf(SAMPLE_SPECS::sample_t **memptr, size_t size) { #ifdef HAVE_POSIX_MEMALIGN /* align buffers to 128bit/16octet boundary */ posix_memalign(reinterpret_cast(memptr), 16, size); #else *memptr = reinterpret_cast(malloc(size)); #endif } /** * Constructs a new sample buffer object. */ SAMPLE_BUFFER::SAMPLE_BUFFER (buf_size_t buffersize, channel_size_t channels) : channel_count_rep(channels), buffersize_rep(buffersize), reserved_samples_rep(buffersize) { // --- DBC_REQUIRE(buffersize >= 0); DBC_REQUIRE(channels >= 0); // --- /* catch if someone changes SAMPLE_SPECS::silent_value */ DBC_DECLARE(float f = 0.0f); DBC_CHECK(static_cast(f) == 0); DBC_CHECK(sizeof(f) == 4); impl_repp = new SAMPLE_BUFFER_impl; buffer.resize(channels); for(size_t n = 0; n < buffer.size(); n++) { priv_alloc_sample_buf(&buffer[n], sizeof(sample_t) * reserved_samples_rep); } make_silent(); impl_repp->rt_lock_rep = false; impl_repp->lockref_rep = 0; impl_repp->old_buffer_repp = 0; #ifdef ECA_COMPILE_SAMPLERATE impl_repp->quality_rep = 50; impl_repp->src_state_rep.resize(channels); #else impl_repp->quality_rep = 5; #endif #ifdef ECA_USE_LIBOIL oil_init(); #endif ECA_LOG_MSG(ECA_LOGGER::functions, "Buffer created, channels: " + kvu_numtostr(buffer.size()) + ", length-samples: " + kvu_numtostr(buffersize_rep) + "."); // --- DBC_ENSURE(buffer.size() == static_cast(channel_count_rep)); // --- } /** * Destructor. */ SAMPLE_BUFFER::~SAMPLE_BUFFER (void) { DBC_CHECK(impl_repp->lockref_rep == 0); for(size_t n = 0; n < buffer.size(); n++) { if (buffer[n] != 0) { ::free(buffer[n]); buffer[n] = 0; } } if (impl_repp->old_buffer_repp != 0) { ::free(impl_repp->old_buffer_repp); impl_repp->old_buffer_repp = 0; } #ifdef ECA_COMPILE_SAMPLERATE for(size_t n = 0; n < impl_repp->src_state_rep.size(); n++) { if (impl_repp->src_state_rep[n] != 0) { src_delete(impl_repp->src_state_rep[n]); impl_repp->src_state_rep[n] = 0; } } #endif delete impl_repp; } /** * Channel-wise addition. Buffer length is increased if necessary. * Only channels, that are present in both source and destination, are * modified. * * Note: event tags are not copied! * * @post length_in_samples() >= x.length_in_samples() */ void SAMPLE_BUFFER::add_matching_channels(const SAMPLE_BUFFER& x) { #ifdef ECA_USE_LIBOIL if (x.length_in_samples() > length_in_samples()) { length_in_samples(x.length_in_samples()); } int min_c_count = (channel_count_rep <= x.channel_count_rep) ? channel_count_rep : x.channel_count_rep; for(channel_size_t q = 0; q < min_c_count; q++) { oil_add_f32(reinterpret_cast(buffer[q]), reinterpret_cast(buffer[q]), reinterpret_cast(x.buffer[q]), x.length_in_samples()); } #else add_matching_channels_ref(x); #endif } /** * Unoptimized version of add_matching_channels(). */ void SAMPLE_BUFFER::add_matching_channels_ref(const SAMPLE_BUFFER& x) { if (x.length_in_samples() > length_in_samples()) { length_in_samples(x.length_in_samples()); } int min_c_count = (channel_count_rep <= x.channel_count_rep) ? channel_count_rep : x.channel_count_rep; for(channel_size_t q = 0; q < min_c_count; q++) { for(buf_size_t t = 0; t < x.length_in_samples(); t++) { buffer[q][t] += x.buffer[q][t]; } } } /** * Channel-wise, weighted addition. Before addition every sample is * multiplied by '1/weight'. Buffer length is increased if necessary. * Only channels, that are present in both source and destination, are * modified. * * Note: event tags are not copied! * * @pre weight != 0 * @post length_in_samples() >= x.length_in_samples() */ void SAMPLE_BUFFER::add_with_weight(const SAMPLE_BUFFER& x, int weight) { // --- DBC_REQUIRE(weight != 0); // --- /* note: gcc does a suprisingly good job for this function, * so additional optimizations don't seem worthwhile */ if (x.length_in_samples() > length_in_samples()) { length_in_samples(x.length_in_samples()); } int min_c_count = (channel_count_rep <= x.channel_count_rep) ? channel_count_rep : x.channel_count_rep; for(channel_size_t q = 0; q < min_c_count; q++) { for(buf_size_t t = 0; t < x.length_in_samples(); t++) { buffer[q][t] += (x.buffer[q][t] / weight); } } } /** * Channel-wise copy. Buffer length is adjusted if necessary. * * Note: event tags are not copied! * * @post length_in_samples() == x.length_in_samples() */ void SAMPLE_BUFFER::copy_matching_channels(const SAMPLE_BUFFER& x) { length_in_samples(x.length_in_samples()); int min_c_count = (channel_count_rep <= x.channel_count_rep) ? channel_count_rep : x.channel_count_rep; for(channel_size_t q = 0; q < min_c_count; q++) { std::memcpy(buffer[q], x.buffer[q], sizeof(sample_t) * length_in_samples()); /* ref implementation: * for(buf_size_t t = 0; t < length_in_samples(); t++) { * buffer[q][t] = x.buffer[q][t]; * } */ } } /** * Copy all audio contents from 'x'. After copying, length, channel * count, and event tag set match to those of 'x'. * * @post length_in_samples() == x.length_in_samples() * @post number_of_channels() == number_of_channels() * @post for all I: event_tag_test(I) == x.event_tag_test(I) */ void SAMPLE_BUFFER::copy_all_content(const SAMPLE_BUFFER& x) { length_in_samples(x.length_in_samples()); number_of_channels(x.number_of_channels()); for(channel_size_t q = 0; q < number_of_channels(); q++) { std::memcpy(buffer[q], x.buffer[q], sizeof(sample_t) * length_in_samples()); /* ref implementation: * { * for(buf_size_t t = 0; t < length_in_samples(); t++) { * buffer[q][t] = x.buffer[q][t]; * } */ } event_tags_set(x); } /** * Ranged channel-wise copy. Copies samples in range * 'start_pos' - 'end_pos-1' from buffer 'x' to current * buffer position 'to_pos'. The 'src' object must have * equal number of channels as the current object. * * Note: event tags are not copied! * * @pre start_pos <= end_pos * @pre * @pre to_pos < length_in_samples() */ void SAMPLE_BUFFER::copy_range(const SAMPLE_BUFFER& src, buf_size_t src_start_pos, buf_size_t src_end_pos, buf_size_t dst_to_pos) { // --- DBC_REQUIRE(src_start_pos <= src_end_pos); DBC_REQUIRE(dst_to_pos < length_in_samples()); DBC_REQUIRE(number_of_channels() == src.number_of_channels()); // --- if (src_end_pos > src.length_in_samples()) src_end_pos = src.length_in_samples(); for(channel_size_t q = 0; q < channel_count_rep; q++) { buf_size_t dst_i = dst_to_pos; for(buf_size_t src_i = src_start_pos; src_i < src_end_pos && dst_i < length_in_samples(); src_i++, dst_i++) { buffer[q][dst_i] = src.buffer[q][src_i]; #ifdef SAMPLEBUFFER_COPY_RANGE_VERBOSE_DEBUG if (dst_i == 0 || src_i == 0 || src_i == src_end_pos - 1 ||dst_i == length_in_samples() - 1) { std::fprintf(stderr, "dst[%d][%ld] = src[%d][%ld]\n", q, dst_i, q, src_i); } #endif } } } void SAMPLE_BUFFER::multiply_by(SAMPLE_BUFFER::sample_t factor, int channel) { #ifdef ECA_USE_LIBOIL oil_scalarmultiply_f32_ns(reinterpret_cast(buffer[channel]), reinterpret_cast(buffer[channel]), reinterpret_cast(&factor), buffersize_rep); #else multiply_by_ref(factor, channel); #endif } void SAMPLE_BUFFER::multiply_by(SAMPLE_BUFFER::sample_t factor) { for(channel_size_t n = 0; n < channel_count_rep; n++) { multiply_by(factor, n); } } void SAMPLE_BUFFER::multiply_by_ref(SAMPLE_BUFFER::sample_t factor) { for(channel_size_t n = 0; n < channel_count_rep; n++) { for(buf_size_t m = 0; m < buffersize_rep; m++) { buffer[n][m] *= factor; } } } void SAMPLE_BUFFER::multiply_by_ref(SAMPLE_BUFFER::sample_t factor, int channel) { for(buf_size_t m = 0; m < buffersize_rep; m++) { buffer[channel][m] *= factor; } } /** * Divides all samples by 'dvalue'. */ void SAMPLE_BUFFER::divide_by(SAMPLE_BUFFER::sample_t dvalue) { multiply_by(1.0 / dvalue); } void SAMPLE_BUFFER::divide_by_ref(SAMPLE_BUFFER::sample_t dvalue) { multiply_by_ref(1.0 / dvalue); } /** * Clears the buffer to zero length. Note that this is * different from a silent buffer. */ void SAMPLE_BUFFER::make_empty(void) { SAMPLE_BUFFER::length_in_samples(0); } /** * Mutes one channel of the buffer. * * @pre channel >= 0 * @pre channel < number_of_channels() */ void SAMPLE_BUFFER::make_silent(int channel) { DBC_REQUIRE(channel >= 0); DBC_REQUIRE(channel < number_of_channels()); std::memset(buffer[channel], 0, buffersize_rep * sizeof(SAMPLE_SPECS::silent_value)); /* - the generic version: */ /* for(buf_size_t s = 0; s < buffersize_rep; s++) { buffer[n][s] = SAMPLE_SPECS::silent_value; } */ } /** * Unoptimized version of make_silent(int). */ void SAMPLE_BUFFER::make_silent_ref(int channel) { for(buf_size_t s = 0; s < buffersize_rep; s++) { buffer[channel][s] = SAMPLE_SPECS::silent_value; } } /** * Mutes the whole buffer. */ void SAMPLE_BUFFER::make_silent(void) { for(channel_size_t n = 0; n < channel_count_rep; n++) { make_silent(n); } } /** * Mute a range of samples. * * @pre start_pos >= 0 * @pre end_pos >= 0 */ void SAMPLE_BUFFER::make_silent_range(buf_size_t start_pos, buf_size_t end_pos) { // -- DBC_REQUIRE(start_pos >= 0); DBC_REQUIRE(end_pos >= 0); // -- for(channel_size_t n = 0; n < channel_count_rep; n++) { std::memset(buffer[n] + start_pos, 0, sizeof(sample_t) * (end_pos < buffersize_rep ? end_pos : buffersize_rep)); } } /** * Unoptimized version of make_silent_range() */ void SAMPLE_BUFFER::make_silent_range_ref(buf_size_t start_pos, buf_size_t end_pos) { // -- DBC_REQUIRE(start_pos >= 0); DBC_REQUIRE(end_pos >= 0); // -- for(channel_size_t n = 0; n < channel_count_rep; n++) { for(buf_size_t s = start_pos; s < end_pos && s < buffersize_rep; s++) { buffer[n][s] = SAMPLE_SPECS::silent_value; } } } /** * Limits all samples to valid values. */ void SAMPLE_BUFFER::limit_values(void) { for(channel_size_t n = 0; n < channel_count_rep; n++) { for(buf_size_t m = 0; m < buffersize_rep; m++) { if (buffer[n][m] > SAMPLE_SPECS::impl_max_value) buffer[n][m] = SAMPLE_SPECS::impl_max_value; else if (buffer[n][m] < SAMPLE_SPECS::impl_min_value) buffer[n][m] = SAMPLE_SPECS::impl_min_value; } } #if 0 /* slower than the naive implementation */ { float min = SAMPLE_SPECS::impl_min_value; float max = SAMPLE_SPECS::impl_max_value; for(channel_size_t n = 0; n < channel_count_rep; n++) { oil_clip_f32(reinterpret_cast(buffer[n]), sizeof(float), reinterpret_cast(buffer[n]), sizeof(float), buffersize_rep, &min, &max); } } #endif } /** Unoptimized version of limit_values() */ void SAMPLE_BUFFER::limit_values_ref(void) { limit_values(); } /** * Resamples samplebuffer contents. Resampling * changes buffer length by 'to_rate/from_rate'. * * @post to_rate / from_rate * old_length_in_samples - length_in_samples() >= -1 */ void SAMPLE_BUFFER::resample(SAMPLE_SPECS::sample_rate_t from_rate, SAMPLE_SPECS::sample_rate_t to_rate) { #ifndef ECA_COMPILE_SAMPLERATE DBC_DECLARE(buf_size_t old_length_in_samples = length_in_samples()); #endif #ifdef ECA_COMPILE_SAMPLERATE if (impl_repp->quality_rep > 5) { resample_secret_rabbit_code(from_rate, to_rate); } else #endif { DBC_CHECK(impl_repp->quality_rep <= 5); resample_with_memory(from_rate, to_rate); } #ifndef ECA_COMPILE_SAMPLERATE /* with libsamplerate, the output sample count can vary from call to call */ DBC_CHECK((static_cast(to_rate) / from_rate * old_length_in_samples - length_in_samples()) >= -1); #endif } /** * Set resampling quality. * * Depending on build options, not all quality levels * are necessarily supported. If the requested quality level * exceeds the available resamplers, the quality setting * is set to the highest available algorithm. You can use * the get_resample_quality() function to query the current level. * * @param quality value between 0 (lowest) to 100 (highest) */ void SAMPLE_BUFFER::resample_set_quality(int quality) { #ifdef ECA_COMPILE_SAMPLERATE impl_repp->quality_rep = quality; #else if (quality > 10) { ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: Libsamplerate is required for high-quality resampling. " "Using the internal resampler instead."); impl_repp->quality_rep = 5; } #endif } /** * Returns current resampling quality. * * @param value between 0 (lowest) to 100 (highest) */ int SAMPLE_BUFFER::resample_get_quality(void) const { return impl_repp->quality_rep; } void SAMPLE_BUFFER::export_helper(unsigned char* obuffer, buf_size_t* optr, sample_t value, ECA_AUDIO_FORMAT::Sample_format fmt) { switch (fmt) { case ECA_AUDIO_FORMAT::sfmt_u8: { obuffer[(*optr)++] = eca_sample_convert_float_to_u8(value); break; } case ECA_AUDIO_FORMAT::sfmt_s16_le: { int16_t s16temp = eca_sample_convert_float_to_s16(value); // little endian: (LSB, MSB) (Intel). obuffer[(*optr)++] = (unsigned char)(s16temp & 0xff); obuffer[(*optr)++] = (unsigned char)((s16temp >> 8) & 0xff); break; } case ECA_AUDIO_FORMAT::sfmt_s16_be: { int16_t s16temp = eca_sample_convert_float_to_s16(value); // big endian: (MSB, LSB) (Motorola). obuffer[(*optr)++] = (unsigned char)((s16temp >> 8) & 0xff); obuffer[(*optr)++] = (unsigned char)(s16temp & 0xff); break; } case ECA_AUDIO_FORMAT::sfmt_s24_le: { int32_t s32temp = eca_sample_convert_float_to_s32(value); /* skip the LSB-byte of s32temp (s32temp & 0xff) */ obuffer[(*optr)++] = (unsigned char)((s32temp >> 8) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 16) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 24) & 0xff); break; } case ECA_AUDIO_FORMAT::sfmt_s24_be: { int32_t s32temp = eca_sample_convert_float_to_s32(value); obuffer[(*optr)++] = (unsigned char)((s32temp >> 24) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 16) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 8) & 0xff); /* skip the LSB-byte of s32temp (s32temp & 0xff) */ break; } case ECA_AUDIO_FORMAT::sfmt_s32_le: { int32_t s32temp = eca_sample_convert_float_to_s32(value); obuffer[(*optr)++] = (unsigned char)(s32temp & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 8) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 16) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 24) & 0xff); break; } case ECA_AUDIO_FORMAT::sfmt_s32_be: { int32_t s32temp = eca_sample_convert_float_to_s32(value); obuffer[(*optr)++] = (unsigned char)((s32temp >> 24) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 16) & 0xff); obuffer[(*optr)++] = (unsigned char)((s32temp >> 8) & 0xff); obuffer[(*optr)++] = (unsigned char)(s32temp & 0xff); break; } case ECA_AUDIO_FORMAT::sfmt_f32_le: { union { int32_t i; float f; } f32temp; f32temp.f = (float)value; obuffer[(*optr)++] = (unsigned char)(f32temp.i & 0xff); obuffer[(*optr)++] = (unsigned char)((f32temp.i >> 8) & 0xff); obuffer[(*optr)++] = (unsigned char)((f32temp.i >> 16) & 0xff); obuffer[(*optr)++] = (unsigned char)((f32temp.i >> 24) & 0xff); break; } case ECA_AUDIO_FORMAT::sfmt_f32_be: { union { int32_t i; float f; } f32temp; f32temp.f = (float)value; obuffer[(*optr)++] = (unsigned char)((f32temp.i >> 24) & 0xff); obuffer[(*optr)++] = (unsigned char)((f32temp.i >> 16) & 0xff); obuffer[(*optr)++] = (unsigned char)((f32temp.i >> 8) & 0xff); obuffer[(*optr)++] = (unsigned char)(f32temp.i & 0xff); break; } default: { ECA_LOG_MSG(ECA_LOGGER::info, "Unknown sample format! [1]."); } } } /** * Exports contents of sample buffer to 'target'. Sample data * will be converted according to the given arguments * (sample format and endianess). If 'chcount > 1', channels * will be written interleaved. * * Note! If chcount > number_of_channels(), empty * channels will be automatically added. * * @pre target != 0 * @pre chcount > 0 * @ensure number_of_channels() >= chcount */ void SAMPLE_BUFFER::export_interleaved(unsigned char* target, ECA_AUDIO_FORMAT::Sample_format fmt, channel_size_t chcount) { // -------- DBC_REQUIRE(target != 0); DBC_REQUIRE(chcount > 0); // -------- if (chcount > channel_count_rep) number_of_channels(chcount); buf_size_t osize = 0; for(buf_size_t isize = 0; isize < buffersize_rep; isize++) { for(channel_size_t c = 0; c < chcount; c++) { sample_t stemp = buffer[c][isize]; if (stemp > SAMPLE_SPECS::impl_max_value) stemp = SAMPLE_SPECS::impl_max_value; else if (stemp < SAMPLE_SPECS::impl_min_value) stemp = SAMPLE_SPECS::impl_min_value; SAMPLE_BUFFER::export_helper(target, &osize, stemp, fmt); } } // ------- DBC_ENSURE(number_of_channels() >= chcount); // ------- } /** * Same as 'export_data()', but 'target' data is * written in non-interleaved format. * * Note! If chcount > number_of_channels(), empty * channels will be automatically added. * * @pre target != 0 * @pre chcount > 0 * @ensure number_of_channels() >= chcount */ void SAMPLE_BUFFER::export_noninterleaved(unsigned char* target, ECA_AUDIO_FORMAT::Sample_format fmt, channel_size_t chcount) { // -------- DBC_REQUIRE(target != 0); DBC_REQUIRE(chcount > 0); // -------- if (chcount > channel_count_rep) number_of_channels(chcount); buf_size_t osize = 0; for(channel_size_t c = 0; c < chcount; c++) { for(buf_size_t isize = 0; isize < buffersize_rep; isize++) { sample_t stemp = buffer[c][isize]; if (stemp > SAMPLE_SPECS::impl_max_value) stemp = SAMPLE_SPECS::impl_max_value; else if (stemp < SAMPLE_SPECS::impl_min_value) stemp = SAMPLE_SPECS::impl_min_value; SAMPLE_BUFFER::export_helper(target, &osize, stemp, fmt); } } // ------- DBC_ENSURE(number_of_channels() >= chcount); // ------- } void SAMPLE_BUFFER::import_helper(const unsigned char *ibuffer, buf_size_t* iptr, sample_t* obuffer, buf_size_t optr, ECA_AUDIO_FORMAT::Sample_format fmt) { unsigned char a[2]; unsigned char b[4]; switch (fmt) { case ECA_AUDIO_FORMAT::sfmt_u8: { obuffer[optr] = eca_sample_convert_u8_to_float(ibuffer[(*iptr)++]); } break; case ECA_AUDIO_FORMAT::sfmt_s16_le: { // little endian: (LSB, MSB) (Intel) // big endian: (MSB, LSB) (Motorola) if (is_system_littleendian) { a[0] = ibuffer[(*iptr)++]; a[1] = ibuffer[(*iptr)++]; } else { a[1] = ibuffer[(*iptr)++]; a[0] = ibuffer[(*iptr)++]; } obuffer[optr] = eca_sample_convert_s16_to_float(*(int16_t*)a); } break; case ECA_AUDIO_FORMAT::sfmt_s16_be: { if (!is_system_littleendian) { a[0] = ibuffer[(*iptr)++]; a[1] = ibuffer[(*iptr)++]; } else { a[1] = ibuffer[(*iptr)++]; a[0] = ibuffer[(*iptr)++]; } obuffer[optr] = eca_sample_convert_s16_to_float(*(int16_t*)a); } break; case ECA_AUDIO_FORMAT::sfmt_s24_le: { if (is_system_littleendian) { b[0] = 0; /* LSB */ b[1] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[3] = ibuffer[(*iptr)++]; } else { b[3] = 0; /* LSB */ b[2] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[0] = ibuffer[(*iptr)++]; } obuffer[optr] = eca_sample_convert_s32_to_float((*(int32_t*)b)); } break; case ECA_AUDIO_FORMAT::sfmt_s24_be: { if (is_system_littleendian) { b[3] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[0] = 0; /* LSB */ } else { b[0] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[3] = 0; /* LSB */ } obuffer[optr] = eca_sample_convert_s32_to_float((*(int32_t*)b)); } break; case ECA_AUDIO_FORMAT::sfmt_s32_le: { if (is_system_littleendian) { b[0] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[3] = ibuffer[(*iptr)++]; } else { b[3] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[0] = ibuffer[(*iptr)++]; } obuffer[optr] = eca_sample_convert_s32_to_float(*(int32_t*)b); } break; case ECA_AUDIO_FORMAT::sfmt_s32_be: { if (is_system_littleendian) { b[3] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[0] = ibuffer[(*iptr)++]; } else { b[0] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[3] = ibuffer[(*iptr)++]; } obuffer[optr] = eca_sample_convert_s32_to_float(*(int32_t*)b); } break; case ECA_AUDIO_FORMAT::sfmt_f32_le: { if (is_system_littleendian) { b[0] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[3] = ibuffer[(*iptr)++]; } else { b[3] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[0] = ibuffer[(*iptr)++]; } obuffer[optr] = (sample_t)(*(float*)b); } break; case ECA_AUDIO_FORMAT::sfmt_f32_be: { if (is_system_littleendian) { b[3] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[0] = ibuffer[(*iptr)++]; } else { b[0] = ibuffer[(*iptr)++]; b[1] = ibuffer[(*iptr)++]; b[2] = ibuffer[(*iptr)++]; b[3] = ibuffer[(*iptr)++]; } obuffer[optr] = (sample_t)(*(float*)b); } break; default: { ECA_LOG_MSG(ECA_LOGGER::info, "Unknown sample format! [4]."); } } } /** * Import audio from external raw buffer. Sample data * will be converted to internal sample format using the * given arguments (sample format and endianess). * Channels will be read interleaved. * * @pre source != 0 * @pre samples_read >= 0 */ void SAMPLE_BUFFER::import_interleaved(unsigned char* source, buf_size_t samples_read, ECA_AUDIO_FORMAT::Sample_format fmt, channel_size_t chcount) { // -------- DBC_REQUIRE(source != 0); DBC_REQUIRE(samples_read >= 0); // -------- if (channel_count_rep != chcount) number_of_channels(chcount); if (buffersize_rep != samples_read) length_in_samples(samples_read); buf_size_t isize = 0; for(buf_size_t osize = 0; osize < buffersize_rep; osize++) { for(channel_size_t c = 0; c < chcount; c++) { import_helper(source, &isize, buffer[c], osize, fmt); } } } /** * Same as 'import_interleaved()', but 'source' data is * assumed to be in non-interleaved format. * * @pre source != 0 * @pre samples_read >= 0 */ void SAMPLE_BUFFER::import_noninterleaved(unsigned char* source, buf_size_t samples_read, ECA_AUDIO_FORMAT::Sample_format fmt, channel_size_t chcount) { // -------- DBC_REQUIRE(source != 0); DBC_REQUIRE(samples_read >= 0); // -------- if (channel_count_rep != chcount) number_of_channels(chcount); if (buffersize_rep != samples_read) length_in_samples(samples_read); buf_size_t isize = 0; for(channel_size_t c = 0; c < chcount; c++) { for(buf_size_t osize = 0; osize < buffersize_rep; osize++) { import_helper(source, &isize, buffer[c], osize, fmt); } } } /** * Sets the number of audio channels. */ void SAMPLE_BUFFER::number_of_channels(channel_size_t len) { // std::cerr << "(samplebuffer_impl) ch-count changes from " << channel_count_rep << " to " << len << ".\n"; if (len > static_cast(buffer.size())) { DBC_CHECK(impl_repp->rt_lock_rep != true); size_t old_size = buffer.size(); buffer.resize(len); for(channel_size_t n = old_size; n < len; n++) { priv_alloc_sample_buf(&buffer[n], sizeof(sample_t) * reserved_samples_rep); } ECA_LOG_MSG(ECA_LOGGER::functions, "Increasing channel-count (1)."); } /* note! channel_count_rep and buffer.size() necessarily * weren't the same before this call, so we need * to double check for old data */ if (len > channel_count_rep) { for(channel_size_t n = channel_count_rep; n < len; n++) { for(buf_size_t m = 0; m < reserved_samples_rep; m++) { buffer[n][m] = SAMPLE_SPECS::silent_value; } } // ECA_LOG_MSG(ECA_LOGGER::system_objects, "Increasing channel-count (2)."); } channel_count_rep = len; } /** * Sets the length of buffer in samples. * * Note: if length is increased, the added samples * are muted. */ void SAMPLE_BUFFER::length_in_samples(buf_size_t len) { DBC_REQUIRE(len >= 0); DBC_CHECK(buffersize_rep <= reserved_samples_rep); if (len > reserved_samples_rep) { DBC_CHECK(impl_repp->rt_lock_rep != true); DBC_CHECK(impl_repp->lockref_rep == 0); reserved_samples_rep = len * 2; for(size_t n = 0; n < buffer.size(); n++) { sample_t *prev_buffer = buffer[n]; priv_alloc_sample_buf(&buffer[n], sizeof(sample_t) * reserved_samples_rep); for (buf_size_t m = 0; m < buffersize_rep; m++) buffer[n][m] = prev_buffer[m]; ::free(prev_buffer); } if (impl_repp->old_buffer_repp != 0) { ::free(impl_repp->old_buffer_repp); priv_alloc_sample_buf(&impl_repp->old_buffer_repp, sizeof(sample_t) * reserved_samples_rep); } } if (len > buffersize_rep) { for(size_t n = 0; n < buffer.size(); n++) { /* note: mute starting from 'buffersize_rep' */ for(buf_size_t m = buffersize_rep; m < reserved_samples_rep; m++) { buffer[n][m] = SAMPLE_SPECS::silent_value; } } } buffersize_rep = len; } /** * Prepares sample buffer object for resampling * operations with params 'from_srate' and * 'to_srate'. This functions is meant for * doing memory allocations and other similar * operations which cannot be performed * with realtime guarantees. */ void SAMPLE_BUFFER::resample_init_memory(SAMPLE_SPECS::sample_rate_t from_srate, SAMPLE_SPECS::sample_rate_t to_srate) { #ifdef ECA_COMPILE_SAMPLERATE ECA_LOG_MSG(ECA_LOGGER::system_objects, "Resampler selected: libsamplerate (Secret Rabbit Code)."); #else ECA_LOG_MSG(ECA_LOGGER::system_objects, "Resampler selected: internal resampler."); #endif double step = 1.0; if (from_srate != 0) { step = static_cast(to_srate) / from_srate; } /* add at least one word of extra space */ buf_size_t new_buffer_size = static_cast((step * buffersize_rep)) + sizeof(buf_size_t); if (new_buffer_size > reserved_samples_rep) { reserved_samples_rep = new_buffer_size * 2; #ifdef ECA_DEBUG_MODE DBC_CHECK(impl_repp->rt_lock_rep != true); DBC_CHECK(impl_repp->lockref_rep == 0); #endif for(int c = 0; c < channel_count_rep; c++) { ::free(buffer[c]); priv_alloc_sample_buf(&buffer[c], sizeof(sample_t) * reserved_samples_rep); } } #ifdef ECA_COMPILE_SAMPLERATE impl_repp->src_state_rep.resize(channel_count_rep); for(int c = 0; c < channel_count_rep; c++) { if (impl_repp->src_state_rep[c] == 0) { int error; impl_repp->src_state_rep[c] = src_new((impl_repp->quality_rep > 75) ? SRC_SINC_BEST_QUALITY : SRC_SINC_MEDIUM_QUALITY, 1, &error); DBC_CHECK(impl_repp->src_state_rep[c] != 0); } } #endif if (impl_repp->old_buffer_repp == 0) { #ifdef ECA_DEBUG_MODE DBC_CHECK(impl_repp->rt_lock_rep != true); #endif priv_alloc_sample_buf(&impl_repp->old_buffer_repp, sizeof(sample_t) * reserved_samples_rep); } if (impl_repp->resample_memory_rep.size() < static_cast(channel_count_rep)) { #ifdef ECA_DEBUG_MODE DBC_CHECK(impl_repp->rt_lock_rep != true); #endif impl_repp->resample_memory_rep.resize(channel_count_rep, 0.0f); } } void SAMPLE_BUFFER::reserve_channels(channel_size_t num) { channel_size_t oldcount = number_of_channels(); number_of_channels(num); number_of_channels(oldcount); } void SAMPLE_BUFFER::reserve_length_in_samples(buf_size_t len) { buf_size_t oldlen = length_in_samples(); length_in_samples(len); length_in_samples(oldlen); } /** * Sets the realtime-lock state. When realtime-lock * is enabled, all non-rt-safe operations * like for instance memory allocations are * blocked. * * @param state true=lock, false=unlock */ void SAMPLE_BUFFER::set_rt_lock(bool state) { impl_repp->rt_lock_rep = state; } /** * Increases reference count of 'buffer' data * area. * * This should be issued when an object uses * direct access to the samplebuffer's * audio data buffer. * * Note! release_pointer_reflock() must be * called after caller stops accessing * 'buffer'. */ void SAMPLE_BUFFER::get_pointer_reflock(void) { impl_repp->lockref_rep++; } /** * Increases reference count of 'buffer' data * area. * * @see get_pointer_reflock() */ void SAMPLE_BUFFER::release_pointer_reflock(void) { impl_repp->lockref_rep--; DBC_ENSURE(impl_repp->lockref_rep >= 0); } /** * Adds all event tags that are set for 'sbuf' (bitwise-OR). */ void SAMPLE_BUFFER::event_tags_add(const SAMPLE_BUFFER& sbuf) { impl_repp->event_tags_rep |= sbuf.impl_repp->event_tags_rep; } /** * Sets only those event flags that are set for 'sbuf'. */ void SAMPLE_BUFFER::event_tags_set(const SAMPLE_BUFFER& sbuf) { impl_repp->event_tags_rep = sbuf.impl_repp->event_tags_rep; } /** * Clears all tags matching 'tagmask' */ void SAMPLE_BUFFER::event_tags_clear(Tag_name tagmask) { event_tag_set(tagmask, false); } /** * Set/clears the event tag 'tag'. */ void SAMPLE_BUFFER::event_tag_set(Tag_name tag, bool val) { if (val) impl_repp->event_tags_rep |= tag; else impl_repp->event_tags_rep &= ~tag; } bool SAMPLE_BUFFER::event_tag_test(Tag_name tag) { return (impl_repp->event_tags_rep & tag) ? true : false; } /** * Resamples samplebuffer contents. * * Note! 'resample_init_memory()' must be called before * before calling this function. */ void SAMPLE_BUFFER::resample_nofilter(SAMPLE_SPECS::sample_rate_t from, SAMPLE_SPECS::sample_rate_t to) { double step = static_cast(to) / from; buf_size_t old_buffer_size = buffersize_rep; // truncate, not round, to integer length_in_samples(static_cast(std::floor(step * buffersize_rep))); DEBUG_RESAMPLING_STATEMENT(std::cerr << "resample_no_f from " << from << " to " << to << "." << std::endl); DBC_CHECK(impl_repp->old_buffer_repp != 0); for(int c = 0; c < channel_count_rep; c++) { std::memcpy(impl_repp->old_buffer_repp, buffer[c], old_buffer_size * sizeof(sample_t)); DBC_CHECK(buffersize_rep <= reserved_samples_rep); double counter = 0.0; buf_size_t new_buffer_index = 0; buf_size_t interpolate_index = 0; buffer[c][0] = impl_repp->old_buffer_repp[0]; for(buf_size_t old_buffer_index = 1; old_buffer_index < old_buffer_size; old_buffer_index++) { counter += step; if (step <= 1) { if (counter >= new_buffer_index + 1) { new_buffer_index++; if (new_buffer_index >= buffersize_rep) break; buffer[c][new_buffer_index] = impl_repp->old_buffer_repp[old_buffer_index]; } } else { new_buffer_index = static_cast(std::ceil(counter)); if (new_buffer_index >= buffersize_rep) new_buffer_index = buffersize_rep - 1; for(buf_size_t t = interpolate_index + 1; t < new_buffer_index; t++) { buffer[c][t] = impl_repp->old_buffer_repp[old_buffer_index - 1] + ((impl_repp->old_buffer_repp[old_buffer_index] - impl_repp->old_buffer_repp[old_buffer_index-1]) * static_cast(t - interpolate_index) / (new_buffer_index - interpolate_index)); } buffer[c][new_buffer_index] = impl_repp->old_buffer_repp[old_buffer_index]; } interpolate_index = new_buffer_index; } } } /** * Resamples samplebuffer contents. * * Note! 'resample_init_memory()' must be called before * before calling this function. */ void SAMPLE_BUFFER::resample_with_memory(SAMPLE_SPECS::sample_rate_t from, SAMPLE_SPECS::sample_rate_t to) { double step = (double)to / from; buf_size_t old_buffer_size = buffersize_rep; // truncate, not round, to integer length_in_samples(static_cast(std::floor(step * buffersize_rep))); DBC_CHECK(impl_repp->old_buffer_repp != 0); DEBUG_RESAMPLING_STATEMENT(std::cerr << "(samplebuffer) resample_w_m from " << from << " to " << to << "." << std::endl); if (impl_repp->resample_memory_rep.size() < static_cast(channel_count_rep)) { DBC_CHECK(impl_repp->rt_lock_rep != true); impl_repp->resample_memory_rep.resize(channel_count_rep, 0.0f); } length_in_samples(buffersize_rep); for(int c = 0; c < channel_count_rep; c++) { std::memcpy(impl_repp->old_buffer_repp, buffer[c], old_buffer_size * sizeof(sample_t)); DBC_CHECK(buffersize_rep <= reserved_samples_rep); double counter = 0.0; buf_size_t new_buffer_index = 0; buf_size_t interpolate_index = -1; sample_t from_point; for(buf_size_t old_buffer_index = 0; old_buffer_index < old_buffer_size; old_buffer_index++) { counter += step; if (step <= 1) { if (counter >= new_buffer_index + 1) { new_buffer_index++; if (new_buffer_index >= buffersize_rep) break; buffer[c][new_buffer_index] = impl_repp->old_buffer_repp[old_buffer_index]; } } else { new_buffer_index = static_cast(std::ceil(counter)); if (old_buffer_index == 0) from_point = impl_repp->resample_memory_rep[c]; else from_point = impl_repp->old_buffer_repp[old_buffer_index-1]; if (new_buffer_index >= buffersize_rep) new_buffer_index = buffersize_rep - 1; for(buf_size_t t = interpolate_index + 1; t < new_buffer_index; t++) { buffer[c][t] = from_point + ((impl_repp->old_buffer_repp[old_buffer_index] - from_point) * static_cast(t - interpolate_index) / (new_buffer_index - interpolate_index)); } buffer[c][new_buffer_index] = impl_repp->old_buffer_repp[old_buffer_index]; } interpolate_index = new_buffer_index; } impl_repp->resample_memory_rep[c] = impl_repp->old_buffer_repp[old_buffer_size - 1]; } } void SAMPLE_BUFFER::resample_secret_rabbit_code(SAMPLE_SPECS::sample_rate_t from_srate, SAMPLE_SPECS::sample_rate_t to_srate) { #ifdef ECA_COMPILE_SAMPLERATE SRC_DATA params; long ch_out_count = -1; double step = static_cast(to_srate) / from_srate; buf_size_t old_buffer_size = buffersize_rep; /* modify buffersize_rep (size of dst buffer) */ length_in_samples(static_cast(std::floor(step * buffersize_rep))); DBC_CHECK(impl_repp->old_buffer_repp != 0); DEBUG_RESAMPLING_STATEMENT(std::cerr << "(samplebuffer) resample_s_r_c from " << from_srate << " to " << to_srate << "." << std::endl); for(int c = 0; c < channel_count_rep; c++) { std::memcpy(impl_repp->old_buffer_repp, buffer[c], old_buffer_size * sizeof(sample_t)); DBC_CHECK(buffersize_rep <= reserved_samples_rep); // A pointer to the input data samples. params.data_in = impl_repp->old_buffer_repp; // The number of frames of data pointed to by data_in. params.input_frames = old_buffer_size; // A pointer to the output data samples. params.data_out = buffer[c]; // Maximum number of frames pointer to by data_out. // note: was 'reserved_samples_rep' but this led // to corrupted output params.output_frames = reserved_samples_rep; /* buffersize_rep; */ // Equal to output_sample_rate / input_sample_rate. params.src_ratio = step; params.end_of_input = 0; // update the step int ret = src_set_ratio(impl_repp->src_state_rep[c], step); DBC_CHECK(ret == 0); // Perform the sample rate conversion ret = src_process(impl_repp->src_state_rep[c], ¶ms); DBC_CHECK(ret == 0); if (ret) { /* make sure we avoid segfault in all cases */ params.output_frames_gen = 0; params.input_frames_used = old_buffer_size; } DBC_CHECK(::labs(params.input_frames_used - old_buffer_size) == 0); #ifdef ECA_DEBUG_MODE /* make sure all input samples have been used */ if (old_buffer_size != params.input_frames_used) { std::cerr << "input_frames_over=" << old_buffer_size - params.input_frames_used << ".\n"; } /* check that all channels are processed in the same way */ if (c == 0) ch_out_count = params.output_frames_gen; DBC_CHECK(ch_out_count == params.output_frames_gen); #endif /* ECA_DEBUG_MODE */ } DEBUG_RESAMPLING_STATEMENT(std::cerr << "(samplebuffer) src_src input=" << old_buffer_size << ", target=" << buffersize_rep << ", processed=" << params.input_frames_used << ", space_for=" << reserved_samples_rep << ", out=" << params.output_frames_gen << std::endl); #ifdef ECA_DEBUG_MODE if ((params.output_frames_gen - buffersize_rep) > 1) { std::cerr << "(samplebuffer) src_src input=" << old_buffer_size << ", target=" << buffersize_rep << ", processed=" << params.input_frames_used << ", space_for=" << reserved_samples_rep << ", out=" << params.output_frames_gen << std::endl; } #endif if (params.output_frames_gen != buffersize_rep) { /* note: we set buffersize_rep directly and bypass * length_in_samples(), but in this case it is safe as * we have used 'reserved_samples_rep' as the upper limit */ buffersize_rep = params.output_frames_gen; } #endif /* ECA_COMPILE_SAMPLERATE */ } void SAMPLE_BUFFER::resample_extfilter(SAMPLE_SPECS::sample_rate_t from_srate, SAMPLE_SPECS::sample_rate_t to_srate) { } void SAMPLE_BUFFER::resample_simplefilter(SAMPLE_SPECS::sample_rate_t from_srate, SAMPLE_SPECS::sample_rate_t to_srate) { }