diff options
Diffstat (limited to 'src/sound/RecordableAudioFile.cpp')
-rw-r--r-- | src/sound/RecordableAudioFile.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/sound/RecordableAudioFile.cpp b/src/sound/RecordableAudioFile.cpp new file mode 100644 index 0000000..09420dd --- /dev/null +++ b/src/sound/RecordableAudioFile.cpp @@ -0,0 +1,164 @@ +// -*- c-basic-offset: 4 -*- + +/* + Rosegarden + A sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <glaurent@telegraph-road.org>, + Chris Cannam <cannam@all-day-breakfast.com>, + Richard Bown <bownie@bownie.com> + + The moral right of the authors to claim authorship of this work + has been asserted. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "RecordableAudioFile.h" + +#include <cstdlib> + +//#define DEBUG_RECORDABLE 1 + +namespace Rosegarden +{ + +RecordableAudioFile::RecordableAudioFile(AudioFile *audioFile, + size_t bufferSize) : + m_audioFile(audioFile), + m_status(IDLE) +{ + for (unsigned int ch = 0; ch < audioFile->getChannels(); ++ch) { + + m_ringBuffers.push_back(new RingBuffer<sample_t>(bufferSize)); + + if (!m_ringBuffers[ch]->mlock()) { + std::cerr << "WARNING: RecordableAudioFile::initialise: couldn't lock buffer into real memory, performance may be impaired" << std::endl; + } + } +} + +RecordableAudioFile::~RecordableAudioFile() +{ + write(); + m_audioFile->close(); + delete m_audioFile; + + for (size_t i = 0; i < m_ringBuffers.size(); ++i) { + delete m_ringBuffers[i]; + } +} + +size_t +RecordableAudioFile::buffer(const sample_t *data, int channel, size_t frames) +{ + if (channel >= int(m_ringBuffers.size())) { + std::cerr << "RecordableAudioFile::buffer: No such channel as " + << channel << std::endl; + return 0; + } + + size_t available = m_ringBuffers[channel]->getWriteSpace(); + + if (frames > available) { + std::cerr << "RecordableAudioFile::buffer: buffer maxed out!" << std::endl; + frames = available; + } + +#ifdef DEBUG_RECORDABLE + std::cerr << "RecordableAudioFile::buffer: buffering " << frames << " frames on channel " << channel << std::endl; +#endif + + m_ringBuffers[channel]->write(data, frames); + return frames; +} + +void +RecordableAudioFile::write() +{ + // Use a static buffer -- this obviously requires that write() is + // only called from a single thread + static size_t bufferSize = 0; + static sample_t *buffer = 0; + static char *encodeBuffer = 0; + + unsigned int bits = m_audioFile->getBitsPerSample(); + + if (bits != 16 && bits != 32) { + std::cerr << "ERROR: RecordableAudioFile::write: file has " << bits + << " bits per sample; only 16 or 32 are supported" << std::endl; + return ; + } + + unsigned int channels = m_audioFile->getChannels(); + unsigned char b1, b2; + + // We need the same amount of available data on every channel + size_t s = 0; + for (unsigned int ch = 0; ch < channels; ++ch) { + size_t available = m_ringBuffers[ch]->getReadSpace(); +#ifdef DEBUG_RECORDABLE + + std::cerr << "RecordableAudioFile::write: " << available << " frames available to write on channel " << ch << std::endl; +#endif + + if (ch == 0 || available < s) + s = available; + } + if (s == 0) + return ; + + size_t bufferReqd = channels * s; + if (bufferReqd > bufferSize) { + if (buffer) { + buffer = (sample_t *)realloc(buffer, bufferReqd * sizeof(sample_t)); + encodeBuffer = (char *)realloc(encodeBuffer, bufferReqd * 4); + } else { + buffer = (sample_t *) malloc(bufferReqd * sizeof(sample_t)); + encodeBuffer = (char *)malloc(bufferReqd * 4); + } + bufferSize = bufferReqd; + } + + for (unsigned int ch = 0; ch < channels; ++ch) { + m_ringBuffers[ch]->read(buffer + ch * s, s); + } + + // interleave and convert + + if (bits == 16) { + size_t index = 0; + for (size_t i = 0; i < s; ++i) { + for (unsigned int ch = 0; ch < channels; ++ch) { + float sample = buffer[i + ch * s]; + b2 = (unsigned char)((long)(sample * 32767.0) & 0xff); + b1 = (unsigned char)((long)(sample * 32767.0) >> 8); + encodeBuffer[index++] = b2; + encodeBuffer[index++] = b1; + } + } + } else { + char *encodePointer = encodeBuffer; + for (size_t i = 0; i < s; ++i) { + for (unsigned int ch = 0; ch < channels; ++ch) { + float sample = buffer[i + ch * s]; + *(float *)encodePointer = sample; + encodePointer += sizeof(float); + } + } + } + +#ifdef DEBUG_RECORDABLE + std::cerr << "RecordableAudioFile::write: writing " << s << " frames at " << channels << " channels and " << bits << " bits to file" << std::endl; +#endif + + m_audioFile->appendSamples(encodeBuffer, s); +} + +} + |