unsigned int SoundSourceCoreAudio::read(unsigned long size, const SAMPLE *destination) { //if (!m_decoder) return 0; OSStatus err; SAMPLE *destBuffer(const_cast<SAMPLE*>(destination)); UInt32 numFrames = 0;//(size / 2); /// m_inputFormat.mBytesPerFrame); unsigned int totalFramesToRead = size/2; unsigned int numFramesRead = 0; unsigned int numFramesToRead = totalFramesToRead; while (numFramesRead < totalFramesToRead) { //FIXME: Hardcoded 2 numFramesToRead = totalFramesToRead - numFramesRead; AudioBufferList fillBufList; fillBufList.mNumberBuffers = 1; //Decode a single track? fillBufList.mBuffers[0].mNumberChannels = m_inputFormat.mChannelsPerFrame; fillBufList.mBuffers[0].mDataByteSize = math_min(1024, numFramesToRead*4);//numFramesToRead*sizeof(*destBuffer); // 2 = num bytes per SAMPLE fillBufList.mBuffers[0].mData = (void*)(&destBuffer[numFramesRead*2]); // client format is always linear PCM - so here we determine how many frames of lpcm // we can read/write given our buffer size numFrames = numFramesToRead; //This silly variable acts as both a parameter and return value. err = ExtAudioFileRead (m_audioFile, &numFrames, &fillBufList); //The actual number of frames read also comes back in numFrames. //(It's both a parameter to a function and a return value. wat apple?) //XThrowIfError (err, "ExtAudioFileRead"); if (!numFrames) { // this is our termination condition break; } numFramesRead += numFrames; } return numFramesRead*2; }
unsigned int SoundSourceFLAC::read(unsigned long size, const SAMPLE *destination) { if (!m_decoder) return 0; SAMPLE *destBuffer(const_cast<SAMPLE*>(destination)); unsigned int samplesWritten = 0; unsigned int i = 0; while (samplesWritten < size) { // if our buffer from libflac is empty (either because we explicitly cleared // it or because we've simply used all the samples), ask for a new buffer if (m_flacBufferLength == 0) { i = 0; if (!FLAC__stream_decoder_process_single(m_decoder)) { qWarning() << "SSFLAC: decoder_process_single returned false"; break; } else if (m_flacBufferLength == 0) { // EOF break; } } destBuffer[samplesWritten++] = m_flacBuffer[i++]; --m_flacBufferLength; } if (m_flacBufferLength != 0) { memcpy(m_leftoverBuffer, &m_flacBuffer[i], m_flacBufferLength * sizeof(m_flacBuffer[0])); // safe because leftoverBuffer // is as long as flacbuffer memcpy(m_flacBuffer, m_leftoverBuffer, m_flacBufferLength * sizeof(m_leftoverBuffer[0])); // this whole if block could go away if this just used a ring buffer but I'd // rather do that after I've gotten off the inital happiness of getting this right, // if I see SIGSEGV one more time I'll pop -- bkgood } return samplesWritten; }
bool CompressStream(Serializer& dest, Deserializer& src) { unsigned srcSize = src.GetSize() - src.GetPosition(); // Prepend the source and dest. data size in the stream so that we know to buffer & uncompress the right amount if (!srcSize) { dest.WriteUInt(0); dest.WriteUInt(0); return true; } unsigned maxDestSize = LZ4_compressBound(srcSize); SharedArrayPtr<unsigned char> srcBuffer(new unsigned char[srcSize]); SharedArrayPtr<unsigned char> destBuffer(new unsigned char[maxDestSize]); if (src.Read(srcBuffer, srcSize) != srcSize) return false; unsigned destSize = LZ4_compressHC((const char*)srcBuffer.Get(), (char*)destBuffer.Get(), srcSize); bool success = true; success &= dest.WriteUInt(srcSize); success &= dest.WriteUInt(destSize); success &= dest.Write(destBuffer, destSize) == destSize; return success; }
void Recognizer::run() { // Create audio converter: auto converter = ci::audio::dsp::Converter::create( mMonitorNode->getSampleRate(), 16000, mMonitorNode->getNumChannels(), 1, mMonitorNode->getFramesPerBlock() ); // Create buffer for converted audio: ci::audio::Buffer destBuffer( converter->getDestMaxFramesPerBlock(), converter->getDestNumChannels() ); bool utt_started, in_speech; if( ps_start_utt( mDecoder ) < 0 ) throw std::runtime_error( "Could not start utterance" ); utt_started = false; while( ! mStop ) { // Convert buffer: std::pair<size_t,size_t> convertResult = converter->convert( &( mMonitorNode->getBuffer() ), &destBuffer ); // Convert buffer data: int16_t* data = new int16_t[ convertResult.second ]; convertFloatToInt16( destBuffer.getData(), data, convertResult.second ); // Process buffer: ps_process_raw( mDecoder, data, convertResult.second, false, false ); // Cleanup buffer data: delete[] data; in_speech = static_cast<bool>( ps_get_in_speech( mDecoder ) ); if( in_speech && ! utt_started ) { utt_started = true; } if( ! in_speech && utt_started ) { // Start new utterance on speech to silence transition: ps_end_utt( mDecoder ); // Pass to handler: if( mHandler ) mHandler->event( mDecoder ); // Prepare for next utterance: if( ps_start_utt( mDecoder ) < 0 ) throw std::runtime_error( "Could not start utterance" ); utt_started = false; } std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); } }
int AudioDecoderCoreAudio::read(int size, const SAMPLE *destination) { OSStatus err; SAMPLE *destBuffer(const_cast<SAMPLE*>(destination)); unsigned int samplesWritten = 0; unsigned int i = 0; UInt32 numFrames = 0; unsigned int totalFramesToRead = size/2; unsigned int numFramesRead = 0; unsigned int numFramesToRead = totalFramesToRead; while (numFramesRead < totalFramesToRead) { numFramesToRead = totalFramesToRead - numFramesRead; AudioBufferList fillBufList; fillBufList.mNumberBuffers = 1; //Decode a single track //See CoreAudioTypes.h for definitins of these variables: fillBufList.mBuffers[0].mNumberChannels = m_clientFormat.NumberChannels(); fillBufList.mBuffers[0].mDataByteSize = numFramesToRead*2 * sizeof(SAMPLE); fillBufList.mBuffers[0].mData = (void*)(&destBuffer[numFramesRead*2]); // client format is always linear PCM - so here we determine how many frames of lpcm // we can read/write given our buffer size numFrames = numFramesToRead; //This silly variable acts as both a parameter and return value. err = ExtAudioFileRead (m_audioFile, &numFrames, &fillBufList); //The actual number of frames read also comes back in numFrames. //(It's both a parameter to a function and a return value. wat apple?) //XThrowIfError (err, "ExtAudioFileRead"); /* if (err != noErr) { std::cerr << "Error reading samples from file" << std::endl; return 0; }*/ if (!numFrames) { // this is our termination condition break; } numFramesRead += numFrames; } m_iPositionInSamples += numFramesRead*m_iChannels; return numFramesRead*m_iChannels; }
bool DecompressStream(Serializer& dest, Deserializer& src) { if (src.IsEof()) return false; unsigned destSize = src.ReadUInt(); unsigned srcSize = src.ReadUInt(); if (!srcSize || !destSize) return true; // No data if (srcSize > src.GetSize()) return false; // Illegal source (packed data) size reported, possibly not valid data SharedArrayPtr<unsigned char> srcBuffer(new unsigned char[srcSize]); SharedArrayPtr<unsigned char> destBuffer(new unsigned char[destSize]); if (src.Read(srcBuffer, srcSize) != srcSize) return false; LZ4_decompress_fast((const char*)srcBuffer.Get(), (char*)destBuffer.Get(), destSize); return dest.Write(destBuffer, destSize) == destSize; }
unsigned int SoundSourceMediaFoundation::read(unsigned long size, const SAMPLE *destination) { if (sDebug) { qDebug() << "read()" << size; } SAMPLE *destBuffer(const_cast<SAMPLE*>(destination)); size_t framesRequested(size / kNumChannels); size_t framesNeeded(framesRequested); // first, copy frames from leftover buffer IF the leftover buffer is at // the correct frame if (m_leftoverBufferLength > 0 && m_leftoverBufferPosition == m_nextFrame) { copyFrames(destBuffer, &framesNeeded, m_leftoverBuffer, m_leftoverBufferLength); if (m_leftoverBufferLength > 0) { if (framesNeeded != 0) { qWarning() << __FILE__ << __LINE__ << "WARNING: Expected frames needed to be 0. Abandoning this file."; m_dead = true; } m_leftoverBufferPosition += framesRequested; } } else { // leftoverBuffer already empty or in the wrong position, clear it m_leftoverBufferLength = 0; } while (!m_dead && framesNeeded > 0) { HRESULT hr(S_OK); DWORD dwFlags(0); qint64 timestamp(0); IMFSample *pSample(NULL); bool error(false); // set to true to break after releasing hr = m_pReader->ReadSample( MF_SOURCE_READER_FIRST_AUDIO_STREAM, // [in] DWORD dwStreamIndex, 0, // [in] DWORD dwControlFlags, NULL, // [out] DWORD *pdwActualStreamIndex, &dwFlags, // [out] DWORD *pdwStreamFlags, ×tamp, // [out] LONGLONG *pllTimestamp, &pSample); // [out] IMFSample **ppSample if (FAILED(hr)) { if (sDebug) { qDebug() << "ReadSample failed."; } break; } if (sDebug) { qDebug() << "ReadSample timestamp:" << timestamp << "frame:" << frameFromMF(timestamp) << "dwflags:" << dwFlags; } if (dwFlags & MF_SOURCE_READERF_ERROR) { // our source reader is now dead, according to the docs qWarning() << "SSMF: ReadSample set ERROR, SourceReader is now dead"; m_dead = true; break; } else if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM) { qDebug() << "SSMF: End of input file."; break; } else if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) { qWarning() << "SSMF: Type change"; break; } else if (pSample == NULL) { // generally this will happen when dwFlags contains ENDOFSTREAM, // so it'll be caught before now -bkgood qWarning() << "SSMF: No sample"; continue; } // we now own a ref to the instance at pSample IMFMediaBuffer *pMBuffer(NULL); // I know this does at least a memcopy and maybe a malloc, if we have // xrun issues with this we might want to look into using // IMFSample::GetBufferByIndex (although MS doesn't recommend this) if (FAILED(hr = pSample->ConvertToContiguousBuffer(&pMBuffer))) { error = true; goto releaseSample; } qint16 *buffer(NULL); size_t bufferLength(0); hr = pMBuffer->Lock(reinterpret_cast<quint8**>(&buffer), NULL, reinterpret_cast<DWORD*>(&bufferLength)); if (FAILED(hr)) { error = true; goto releaseMBuffer; } bufferLength /= (kBitsPerSample / 8 * kNumChannels); // now in frames if (m_seeking) { qint64 bufferPosition(frameFromMF(timestamp)); if (sDebug) { qDebug() << "While seeking to " << m_nextFrame << "WMF put us at" << bufferPosition; } if (m_nextFrame < bufferPosition) { // Uh oh. We are farther forward than our seek target. Emit // silence? We can't seek backwards here. SAMPLE* pBufferCurpos = destBuffer + (size - framesNeeded * kNumChannels); qint64 offshootFrames = bufferPosition - m_nextFrame; // If we can correct this immediately, write zeros and adjust // m_nextFrame to pretend it never happened. if (offshootFrames <= framesNeeded) { qWarning() << __FILE__ << __LINE__ << "Working around inaccurate seeking. Writing silence for" << offshootFrames << "frames"; // Set offshootFrames * kNumChannels samples to zero. memset(pBufferCurpos, 0, sizeof(*pBufferCurpos) * offshootFrames * kNumChannels); // Now m_nextFrame == bufferPosition m_nextFrame += offshootFrames; framesNeeded -= offshootFrames; } else { // It's more complicated. The buffer we have just decoded is // more than framesNeeded frames away from us. It's too hard // for us to handle this correctly currently, so let's just // try to get on with our lives. m_seeking = false; m_nextFrame = bufferPosition; qWarning() << __FILE__ << __LINE__ << "Seek offshoot is too drastic. Cutting losses and pretending the current decoded audio buffer is the right seek point."; } } if (m_nextFrame >= bufferPosition && m_nextFrame < bufferPosition + bufferLength) { // m_nextFrame is in this buffer. buffer += (m_nextFrame - bufferPosition) * kNumChannels; bufferLength -= m_nextFrame - bufferPosition; m_seeking = false; } else { // we need to keep going forward goto releaseRawBuffer; } } // If the bufferLength is larger than the leftover buffer, re-allocate // it with 2x the space. if (bufferLength * kNumChannels > m_leftoverBufferSize) { int newSize = m_leftoverBufferSize; while (newSize < bufferLength * kNumChannels) { newSize *= 2; } qint16* newBuffer = new qint16[newSize]; memcpy(newBuffer, m_leftoverBuffer, sizeof(m_leftoverBuffer[0]) * m_leftoverBufferSize); delete [] m_leftoverBuffer; m_leftoverBuffer = newBuffer; m_leftoverBufferSize = newSize; } copyFrames(destBuffer + (size - framesNeeded * kNumChannels), &framesNeeded, buffer, bufferLength); releaseRawBuffer: hr = pMBuffer->Unlock(); // I'm ignoring this, MSDN for IMFMediaBuffer::Unlock stipulates // nothing about the state of the instance if this fails so might as // well just let it be released. //if (FAILED(hr)) break; releaseMBuffer: safeRelease(&pMBuffer); releaseSample: safeRelease(&pSample); if (error) break; } m_nextFrame += framesRequested - framesNeeded; if (m_leftoverBufferLength > 0) { if (framesNeeded != 0) { qWarning() << __FILE__ << __LINE__ << "WARNING: Expected frames needed to be 0. Abandoning this file."; m_dead = true; } m_leftoverBufferPosition = m_nextFrame; } long samples_read = size - framesNeeded * kNumChannels; m_iCurrentPosition += samples_read; if (sDebug) { qDebug() << "read()" << size << "returning" << samples_read; } return samples_read; }