void AudioBuffer::convert_rate(AudioBuffer &_dest, unsigned _frames_count, SRC_STATE *_SRC) { AudioSpec destspec{AUDIO_FORMAT_F32, m_spec.channels, _dest.rate()}; if(m_spec.format != AUDIO_FORMAT_F32 || _dest.spec() != destspec) { throw std::logic_error("unsupported format"); } _frames_count = std::min(frames(),_frames_count); double rate_ratio = double(destspec.rate)/double(m_spec.rate); unsigned out_frames = unsigned(ceil(double(_frames_count) * rate_ratio)); if(out_frames==0) { return; } unsigned destpos = _dest.samples(); unsigned destframes = _dest.frames(); _dest.resize_frames(_dest.frames()+out_frames); #if HAVE_LIBSAMPLERATE SRC_DATA srcdata; srcdata.data_in = &at<float>(0); srcdata.data_out = &_dest.at<float>(destpos); srcdata.input_frames = _frames_count; srcdata.output_frames = out_frames; srcdata.src_ratio = rate_ratio; int srcresult; if(_SRC != nullptr) { srcdata.end_of_input = 0; srcresult = src_process(_SRC, &srcdata); } else { srcdata.end_of_input = 1; srcresult = src_simple(&srcdata, SRC_SINC_BEST_QUALITY, destspec.channels) ; } if(srcresult != 0) { throw std::runtime_error(std::string("error resampling: ") + src_strerror(srcresult)); } assert(srcdata.output_frames_gen>=0 && srcdata.output_frames_gen<=out_frames); if(srcdata.output_frames_gen != out_frames) { _dest.resize_frames(destframes + srcdata.output_frames_gen); } PDEBUGF(LOG_V2, LOG_MIXER, "convert rate: f-in: %d, f-out: %d, gen: %d\n", _frames_count, out_frames, srcdata.output_frames_gen); #else for(unsigned i=destpos; i<_dest.samples(); ++i) { _dest.operator[]<float>(i) = 0.f; } #endif }
// This one puts some data inside the ring buffer. void RingBuffer::put(AudioBuffer& buf) { std::lock_guard<std::mutex> l(lock_); const size_t sample_num = buf.frames(); const size_t buffer_size = buffer_.frames(); if (buffer_size == 0) return; size_t len = putLength(); if (buffer_size - len < sample_num) discard(sample_num); size_t toCopy = sample_num; // Add more channels if the input buffer holds more channels than the ring. if (buffer_.channels() < buf.channels()) buffer_.setChannelNum(buf.channels()); size_t in_pos = 0; size_t pos = endPos_; while (toCopy) { size_t block = toCopy; if (block > buffer_size - pos) // Wrap block around ring ? block = buffer_size - pos; // Fill in to the end of the buffer buffer_.copy(buf, block, in_pos, pos); in_pos += block; pos = (pos + block) % buffer_size; toCopy -= block; } endPos_ = pos; not_empty_.notify_all(); }
void AudioBuffer::convert(const AudioSpec &_new_spec) { if(_new_spec == m_spec) { return; } AudioSpec new_spec = _new_spec; AudioBuffer dest[2]; unsigned bufidx = 0; AudioBuffer *source = this; if(source->rate() != new_spec.rate) { #if HAVE_LIBSAMPLERATE if(source->format() != AUDIO_FORMAT_F32) { dest[1].set_spec({AUDIO_FORMAT_F32, source->channels(), source->rate()}); source->convert_format(dest[1], source->frames()); source = &dest[1]; } dest[0].set_spec({source->format(), source->channels(), new_spec.rate}); source->convert_rate(dest[0], source->frames(), nullptr); source = &dest[0]; bufidx = 1; #else new_spec.rate = source->rate(); #endif } if(source->channels() != new_spec.channels) { dest[bufidx].set_spec({source->format(),new_spec.channels,source->rate()}); source->convert_channels(dest[bufidx], source->frames()); source = &dest[bufidx]; bufidx = (bufidx + 1) % 2; } if(source->format() != new_spec.format) { dest[bufidx].set_spec({new_spec.format,source->channels(),source->rate()}); source->convert_format(dest[bufidx], source->frames()); source = &dest[bufidx]; } if(new_spec != m_spec) { m_data = source->m_data; m_spec = new_spec; } }
void AudioBuffer::add_frames(const AudioBuffer &_source, unsigned _frames_count) { if(_source.spec() != m_spec) { throw std::logic_error("sound buffers must have the same spec"); } _frames_count = std::min(_frames_count, _source.frames()); if(_frames_count == 0) { return; } unsigned datalen = _frames_count * frame_size(); auto srcstart = _source.m_data.begin(); m_data.insert(m_data.end(), srcstart, srcstart+datalen); }
void Resampler::resample(const AudioBuffer &dataIn, AudioBuffer &dataOut) { const double inputFreq = dataIn.getSampleRate(); const double outputFreq = dataOut.getSampleRate(); const double sampleFactor = outputFreq / inputFreq; if (sampleFactor == 1.0) return; const size_t nbFrames = dataIn.frames(); const size_t nbChans = dataIn.channels(); if (nbChans != format_.nb_channels) { // change channel num if needed int err; src_delete(src_state_); src_state_ = src_new(SRC_LINEAR, nbChans, &err); format_.nb_channels = nbChans; DEBUG("SRC channel number changed."); } if (nbChans != dataOut.channels()) { DEBUG("Output buffer had the wrong number of channels (in: %d, out: %d).", nbChans, dataOut.channels()); dataOut.setChannelNum(nbChans); } size_t inSamples = nbChans * nbFrames; size_t outSamples = inSamples * sampleFactor; // grow buffer if needed floatBufferIn_.resize(inSamples); floatBufferOut_.resize(outSamples); scratchBuffer_.resize(outSamples); SRC_DATA src_data; src_data.data_in = floatBufferIn_.data(); src_data.data_out = floatBufferOut_.data(); src_data.input_frames = nbFrames; src_data.output_frames = nbFrames * sampleFactor; src_data.src_ratio = sampleFactor; src_data.end_of_input = 0; // More data will come dataIn.interleaveFloat(floatBufferIn_.data()); src_process(src_state_, &src_data); /* TODO: one-shot deinterleave and float-to-short conversion */ src_float_to_short_array(floatBufferOut_.data(), scratchBuffer_.data(), outSamples); dataOut.deinterleave(scratchBuffer_.data(), src_data.output_frames, nbChans); }
void JackLayer::write(AudioBuffer &buffer, std::vector<float> &floatBuffer) { for (unsigned i = 0; i < out_ringbuffers_.size(); ++i) { const unsigned inChannel = std::min(i, buffer.channels() - 1); convertToFloat(*buffer.getChannel(inChannel), floatBuffer); // write to output const size_t to_ringbuffer = jack_ringbuffer_write_space(out_ringbuffers_[i]); const size_t write_bytes = std::min(buffer.frames() * sizeof(floatBuffer[0]), to_ringbuffer); // FIXME: while we have samples to write AND while we have space to write them const size_t written_bytes = jack_ringbuffer_write(out_ringbuffers_[i], (const char *) floatBuffer.data(), write_bytes); if (written_bytes < write_bytes) RING_WARN("Dropped %zu bytes for channel %u", write_bytes - written_bytes, i); } }
void OpenSLLayer::audioCaptureFillBuffer(AudioBuffer &buffer) { RingBufferPool &mbuffer = Manager::instance().getRingBufferPool(); const AudioFormat mainBufferFormat = mbuffer.getInternalAudioFormat(); const bool resample = mainBufferFormat.sample_rate != audioFormat_.sample_rate; buffer.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); if (resample) { int outSamples = buffer.frames() * (static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate); AudioBuffer out(outSamples, mainBufferFormat); resampler_->resample(buffer, out); dcblocker_.process(out); mainRingBuffer_->put(out); } else { dcblocker_.process(buffer); mainRingBuffer_->put(buffer); } }
size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id) { std::lock_guard<std::mutex> l(lock_); if (hasNoReadOffsets()) return 0; if (not hasThisReadOffset(call_id)) return 0; const size_t buffer_size = buffer_.frames(); if (buffer_size == 0) return 0; size_t len = getLength(call_id); const size_t sample_num = buf.frames(); size_t toCopy = std::min(sample_num, len); if (toCopy and toCopy != sample_num) { RING_DBG("Partial get: %zu/%zu", toCopy, sample_num); } const size_t copied = toCopy; size_t dest = 0; size_t startPos = getReadOffset(call_id); while (toCopy > 0) { size_t block = toCopy; if (block > buffer_size - startPos) block = buffer_size - startPos; buf.copy(buffer_, block, startPos, dest); dest += block; startPos = (startPos + block) % buffer_size; toCopy -= block; } storeReadOffset(startPos, call_id); return copied; }
void AudioBuffer::convert_channels(const AudioBuffer &_source, AudioBuffer &_dest, unsigned _frames_count) { unsigned d = _dest.samples(); _dest.resize_frames(_dest.frames()+_frames_count); if(_source.channels()==1 && _dest.channels()==2) { //from mono to stereo for(unsigned i=0; i<_frames_count; ++i) { T ch1 = _source.at<T>(i); _dest.operator[]<T>(d+i*2) = ch1; _dest.operator[]<T>(d+i*2+1) = ch1; } } else if(_source.channels()==2 && _dest.channels()==1) { //from stereo to mono for(unsigned i=0; i<_frames_count; ++i) { double ch1 = double(_source.at<T>(i*2)); double ch2 = double(_source.at<T>(i*2+1)); _dest.operator[]<T>(d+i) = T((ch1 + ch2) / 2.0); } } }
size_t RingBufferPool::getAvailableData(AudioBuffer& buffer, const std::string& call_id) { std::lock_guard<std::recursive_mutex> lk(stateLock_); auto bindings = getReadBindings(call_id); if (not bindings) return 0; // No mixing if (bindings->size() == 1) { return (*bindings->cbegin())->get(buffer, call_id); } size_t availableSamples = std::numeric_limits<size_t>::max(); for (const auto& rbuf : *bindings) availableSamples = std::min(availableSamples, rbuf->availableForGet(call_id)); if (availableSamples == std::numeric_limits<size_t>::max()) return 0; availableSamples = std::min(availableSamples, buffer.frames()); buffer.resize(availableSamples); buffer.reset(); buffer.setFormat(internalAudioFormat_); AudioBuffer mixBuffer(buffer); for (const auto &rbuf : *bindings) { if (rbuf->get(mixBuffer, call_id) > 0) buffer.mix(mixBuffer); } return availableSamples; }
void AudioBuffer::add_frames(const AudioBuffer &_source) { add_frames(_source, _source.frames()); }