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);
}