ITADataSourceRealization.cpp 5.42 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1 2
#include "ITADataSourceRealization.h"
#include <ITAFastMath.h>
3
#include <cassert>
Jonas Stienen's avatar
Jonas Stienen committed
4

5
ITADatasourceRealization::ITADatasourceRealization( unsigned int uiChannels, double dSamplerate, unsigned int uiBlocklength, unsigned int uiCapacity )
Jonas Stienen's avatar
Jonas Stienen committed
6 7
{
	assert( dSamplerate > 0 );
8
	m_dSampleRate = dSamplerate;
Jonas Stienen's avatar
Jonas Stienen committed
9 10
	m_oStreamProps.dSamplerate = dSamplerate;

11 12
	Init( uiChannels, uiBlocklength, uiCapacity );
}
Jonas Stienen's avatar
Jonas Stienen committed
13

14
void ITADatasourceRealization::Init( unsigned int uiChannels, unsigned int uiBlocklength, unsigned int uiCapacity )
Jonas Stienen's avatar
Jonas Stienen committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
{
	assert( uiChannels > 0 );
	assert( uiBlocklength > 0 );
	assert( uiCapacity > 0 );

	// Interne Felder setzen

	/*
	 *  Hinweis: m_uiBufferSize ist nicht die Lnge des gesamten Puffers,
	 *           sondern nur die Lnge der Blcke EINES Kanals. Des Weiteren
	 *           ist der Puffer ein Element grer als die Kapazitt, damit
	 *           Anzahl Kapazitt Blcke vorausgespeichert werden knnen.
	 */

	m_uiChannels = uiChannels;
	m_uiBlocklength = uiBlocklength;

32
	m_oStreamProps.dSamplerate = m_dSampleRate;
Jonas Stienen's avatar
Jonas Stienen committed
33 34 35
	m_oStreamProps.uiChannels = m_uiChannels;
	m_oStreamProps.uiBlocklength = m_uiBlocklength;

36
	m_uiBufferSize = uiBlocklength * ( uiCapacity + 1 );
Jonas Stienen's avatar
Jonas Stienen committed
37 38 39 40 41 42 43

	m_pEventHandler = NULL;

	/*
	   Organisation des Puffers: Damit die Blcke der einzelnen Kanle
	   im Speicher ortlich nher liegen ist das Array wiefolgt indiziert:

44
	   [1. Block Kanal 1], ..., [1. Block Kanal k], [2. Block Kanal 1], ...
Jonas Stienen's avatar
Jonas Stienen committed
45

46
	   */
Jonas Stienen's avatar
Jonas Stienen committed
47 48 49 50

	// Puffer erzeugen und mit Nullen initialiseren
	// TODO: Fehlerbehandlung beim Speicherallozieren
	/* Bugfix zu Bug #001:
51

Jonas Stienen's avatar
Jonas Stienen committed
52 53 54 55
	   Hier wurde der Puffer einfach um 1024 Felder verlngert.
	   Damit Funktioniert Wuschels ASIO4ALL jetzt. Ungeklrt aber
	   warum der Fehler auftrat?

56 57
	   2005-2-14
	   */
Jonas Stienen's avatar
Jonas Stienen committed
58

59
	m_pfBuffer = fm_falloc( m_uiBufferSize * m_uiChannels + /* >>> */ 1024 /* <<< */, false );
Jonas Stienen's avatar
Jonas Stienen committed
60

61
	Reset();
Jonas Stienen's avatar
Jonas Stienen committed
62 63
}

64 65 66
ITADatasourceRealization::~ITADatasourceRealization()
{
	fm_free( m_pfBuffer );
Jonas Stienen's avatar
Jonas Stienen committed
67 68
}

69 70
void ITADatasourceRealization::Reset()
{
Jonas Stienen's avatar
Jonas Stienen committed
71 72 73 74 75 76 77 78 79 80 81
	m_uiReadCursor = 0;
	m_uiWriteCursor = 0;

	// Fehler-Indikatoren zurcksetzen
	m_iBufferUnderflows = 0;
	m_iBufferOverflows = 0;
	m_iGBPReentrances = 0;

	m_iGBPEntrances = 0;
	m_bGBPFirst = true;

82
	fm_zero( m_pfBuffer, m_uiBufferSize * m_uiChannels + /* >>> */ 1024 /* <<< */ );
Jonas Stienen's avatar
Jonas Stienen committed
83 84
}

85 86 87
bool ITADatasourceRealization::HasStreamErrors() const
{
	return ( m_iBufferUnderflows > 0 ) || ( m_iBufferOverflows > 0 ) || ( m_iGBPReentrances > 0 );
Jonas Stienen's avatar
Jonas Stienen committed
88 89
}

90 91
ITADatasourceRealizationEventHandler* ITADatasourceRealization::GetStreamEventHandler() const
{
Jonas Stienen's avatar
Jonas Stienen committed
92 93 94
	return m_pEventHandler;
}

95 96
void ITADatasourceRealization::SetStreamEventHandler( ITADatasourceRealizationEventHandler* pHandler )
{
Jonas Stienen's avatar
Jonas Stienen committed
97 98 99
	m_pEventHandler = pHandler;
}

100 101
const float* ITADatasourceRealization::GetBlockPointer( unsigned int uiChannel, const ITAStreamInfo* pStreamInfo )
{
Jonas Stienen's avatar
Jonas Stienen committed
102 103 104 105 106 107 108 109
	assert( uiChannel < m_uiChannels );

	/*
	 * Parallele Wiedereintritte in GBP bedeutet, das die Rechenzeit berschritten wurde
	 * und die Audio-Hardware bereits die nchste Runde im Stream eingelutet hat.
	 *
	 * WICHTIG: Dies sollte nicht passieren. Fehler beim anwendenden Programmierer!
	 */
110 111
	if( ++m_iGBPEntrances > 1 )
	{
Jonas Stienen's avatar
Jonas Stienen committed
112 113 114 115 116 117 118
		--m_iGBPEntrances;
		++m_iGBPReentrances;
		return NULL;
	}

	// Hook/Handler aufrufen
	PreGetBlockPointer();
119 120
	if( m_pEventHandler )
		m_pEventHandler->HandlePreGetBlockPointer( this, uiChannel );
Jonas Stienen's avatar
Jonas Stienen committed
121

122 123
	if( m_bGBPFirst )
	{
Jonas Stienen's avatar
Jonas Stienen committed
124
		// Erster Eintritt in GBP seit letztem IBP => Daten produzieren
125 126 127 128
		ProcessStream( pStreamInfo );

		if( m_pEventHandler )
			m_pEventHandler->HandleProcessStream( this, pStreamInfo );
Jonas Stienen's avatar
Jonas Stienen committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142

		m_bGBPFirst = false;
	}

	/*
	 *  Semantik: Daten im Puffer <=> Read cursor != write cursor
	 *
	 *  Beim letzen Aufruf von ProcessStream wurden keine weiteren Daten in
	 *  den Ausgabepuffer gelegt und nun ist dieser Leer. Daher Nullzeiger zurckgeben.
	 *
	 *  WICHTIG: Dies sollte nicht passieren. Fehler beim anwendenden Programmierer!
	 */

	unsigned int uiLocalReadCursor = m_uiReadCursor;
143 144
	if( uiLocalReadCursor == m_uiWriteCursor )
	{
Jonas Stienen's avatar
Jonas Stienen committed
145 146 147 148 149 150
		++m_iBufferUnderflows;
		--m_iGBPEntrances;
		return NULL;
	}

	--m_iGBPEntrances;
151
	return m_pfBuffer + ( uiChannel * m_uiBufferSize ) + uiLocalReadCursor;
Jonas Stienen's avatar
Jonas Stienen committed
152 153
}

154 155
void ITADatasourceRealization::IncrementBlockPointer()
{
Jonas Stienen's avatar
Jonas Stienen committed
156 157
	unsigned int uiLocalReadCursor = m_uiReadCursor;

158
	if( uiLocalReadCursor == m_uiWriteCursor )
Jonas Stienen's avatar
Jonas Stienen committed
159 160 161 162
		// Keine Daten im Ausgabepuffer? Kein Inkrement mglich! (Fehlerfall)
		++m_iBufferUnderflows;
	else
		// Lesezeiger inkrementieren
163
		m_uiReadCursor = ( uiLocalReadCursor + m_uiBlocklength ) % m_uiBufferSize;
Jonas Stienen's avatar
Jonas Stienen committed
164 165 166 167

	m_bGBPFirst = true;

	PostIncrementBlockPointer();
168 169 170

	if( m_pEventHandler )
		m_pEventHandler->HandlePostIncrementBlockPointer( this );
Jonas Stienen's avatar
Jonas Stienen committed
171 172
}

173 174
float* ITADatasourceRealization::GetWritePointer( unsigned int uiChannel )
{
Jonas Stienen's avatar
Jonas Stienen committed
175
	assert( uiChannel < m_uiChannels );
176
	return m_pfBuffer + ( uiChannel * m_uiBufferSize ) + m_uiWriteCursor;
Jonas Stienen's avatar
Jonas Stienen committed
177 178
}

179 180
void ITADatasourceRealization::IncrementWritePointer()
{
Jonas Stienen's avatar
Jonas Stienen committed
181 182
	// Lokaler Schreibcursor
	unsigned int uiLocalWriteCursor = m_uiWriteCursor;
183
	unsigned int uiNewWriteCursor = ( uiLocalWriteCursor + m_uiBlocklength ) % m_uiBufferSize;
Jonas Stienen's avatar
Jonas Stienen committed
184 185

	// Pufferberlauf
186 187
	if( uiNewWriteCursor == m_uiReadCursor )
	{
Jonas Stienen's avatar
Jonas Stienen committed
188 189 190 191 192 193 194 195
		++m_iBufferOverflows;
		return;
	}

	// Neuen Schreibcursor setzen
	m_uiWriteCursor = uiNewWriteCursor;
}

196 197 198
void ITADatasourceRealizationEventHandler::HandlePreGetBlockPointer( ITADatasourceRealization*, unsigned int ) {}
void ITADatasourceRealizationEventHandler::HandlePostIncrementBlockPointer( ITADatasourceRealization* ) {}
void ITADatasourceRealizationEventHandler::HandleProcessStream( ITADatasourceRealization*, const ITAStreamInfo* ) {}