ITABufferedAudioFileWriter.cpp 3.25 KB
Newer Older
js908001's avatar
js908001 committed
1
#include <ITABufferedAudioFileWriter.h>
Jonas Stienen's avatar
Jonas Stienen committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

#include <ITAException.h>
#include <ITASampleFrame.h>

#include <algorithm>
#include <list>
#include <algorithm>
#include <math.h>


class ITABufferedAudiofileWriterImpl : public ITABufferedAudiofileWriter
{
public:
	inline ITABufferedAudiofileWriterImpl(std::string sFilename,
		                           const ITAAudiofileProperties& props,
								   double dInitialBufferSizeSeconds,
								   double dGrowBufferSizeSeconds)
	: m_pWriter(NULL)
	{
		// Zunächst versuchen den regulären (ungepufferten) Schreiber aufzusetzen
		m_pWriter = ITAAudiofileWriter::create(sFilename, props);

		// Initialen Chunk anlegen
		m_iInitialBufferSizeSamples = (int) ceil( dInitialBufferSizeSeconds*props.dSamplerate );
		m_iGrowBufferSizeSamples = (int)  ceil( dGrowBufferSizeSeconds*props.dSamplerate );

		m_lpChunks.push_back( new Chunk( (int) props.uiChannels, m_iInitialBufferSizeSamples ) );
	}

	inline virtual ~ITABufferedAudiofileWriterImpl() {
		// Alle Chunks schreiben und freigeben
		for (std::list<Chunk*>::iterator it=m_lpChunks.begin(); it!=m_lpChunks.end(); ++it) {
			Chunk* pChunk = (*it);
			
			if (m_pWriter && (pChunk->m_iTail > 0))
				m_pWriter->write(pChunk->m_iTail, pChunk->m_vpfData);

			delete pChunk;
		}

		// Schreiber freigeben
		delete m_pWriter;
	}

	inline virtual void write( unsigned int uiLength, std::vector<const float*> vpfSource ) {
		// Korrekte Anzahl Kanäle
		int iChannels = m_lpChunks.back()->m_sfSamples.channels();
		if ((int) vpfSource.size() != iChannels)
			ITA_EXCEPT1(INVALID_PARAMETER, "Wrong number of channels in source data");

		if (uiLength == 0) return;
		
		int iWritten = 0;
		int iTotal = (int) uiLength;
		int iRemain = iTotal;
		
		while (iWritten < iTotal) {
			Chunk* pTailChunk = m_lpChunks.back();
			
			// Soviel in diesen Chunk schreiben wie möglich
			int iChunkRemain = pTailChunk->m_sfSamples.length() - pTailChunk->m_iTail;
			int iCount = std::min( iRemain, iChunkRemain );

			for (int i=0; i<iChannels; i++)
				pTailChunk->m_sfSamples[i].write( vpfSource[i], iCount, pTailChunk->m_iTail );
			pTailChunk->m_iTail += iCount;

			iWritten += iCount;
			iRemain = iTotal - iWritten;

			// Neuen Chunk anlegen, falls noch Daten zu schreiben ...
			if (iRemain > 0) {
				m_lpChunks.push_back( new Chunk( iChannels, m_iGrowBufferSizeSamples) );
			}
		}
	}

private:
	// Interner Speicherblock für Samples
	class Chunk
	{
	public:
		ITASampleFrame m_sfSamples;
		std::vector<float*> m_vpfData; // Zugriffszeiger auf Kanaldaten (für den Writer)
		int m_iTail;

		inline Chunk( int iChannels, int iCapacity )
		: m_sfSamples( iChannels, iCapacity, false )
		, m_vpfData(iChannels)
		, m_iTail(0)
		{
			for( int i=0; i<iChannels; i++ )
				m_vpfData[i] = m_sfSamples[i].GetData();
		}
	};

	ITAAudiofileWriter* m_pWriter;
	std::list<Chunk*> m_lpChunks;
	int m_iInitialBufferSizeSamples;
	int m_iGrowBufferSizeSamples;
};


ITABufferedAudiofileWriter* ITABufferedAudiofileWriter::create(const std::string& sFilename,
													           const ITAAudiofileProperties& props,
													           double dInitialBufferSizeSeconds,
													           double dGrowBufferSizeSeconds)
{
	return new ITABufferedAudiofileWriterImpl(sFilename, props, dInitialBufferSizeSeconds, dGrowBufferSizeSeconds);
}