Commit d84daa74 authored by Dipl.-Ing. Jonas Stienen's avatar Dipl.-Ing. Jonas Stienen
Browse files

Cleanup, refactoring and changing buffered audio file writer behaviour to...

Cleanup, refactoring and changing buffered audio file writer behaviour to enable lazy file path setting
parent 76518819
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <ITABaseDefinitions.h> #include <ITABaseDefinitions.h>
#include <ITAAudiofileWriter.h> #include <ITAAudiofileWriter.h>
//! Audio file writer that first buffers samples and exports on demand or destruction
/** /**
* Klasse welche Schreiber von Audiodateien um Pufferung erweitert. * Klasse welche Schreiber von Audiodateien um Pufferung erweitert.
* Dies ist u.A. wichtig in der Echtzeit-Verarbeitung, wobei keine * Dies ist u.A. wichtig in der Echtzeit-Verarbeitung, wobei keine
...@@ -34,15 +35,25 @@ ...@@ -34,15 +35,25 @@
* werden. Wird diese Aufgebraucht, wird der Puffer automatisch um die * werden. Wird diese Aufgebraucht, wird der Puffer automatisch um die
* angegebene Wachstumsgröße erweitert. * angegebene Wachstumsgröße erweitert.
*/ */
class ITA_BASE_API ITABufferedAudiofileWriter : public ITAAudiofileWriter class ITA_BASE_API ITABufferedAudiofileWriter : public ITAAudiofileWriter
{ {
public: public:
//! Factory method. Erzeugt einen gepufferten Schreiber. //! Factory method. Erzeugt einen gepufferten Schreiber.
static ITABufferedAudiofileWriter* create(const std::string& sFilename, static ITABufferedAudiofileWriter* create( const ITAAudiofileProperties& props, double dInitialBufferSizeSeconds = 60, double dGrowBufferSizeSeconds = 20 );
const ITAAudiofileProperties& props,
double dInitialBufferSizeSeconds=60, //! Returns current file path or empty string
double dGrowBufferSizeSeconds=20); /**
* @return Current file path or empty string
*
*/
virtual std::string GetFilePath() const = 0;
//! Sets the export file path (without any checks)
/**
* @param[in] sFilePath File path (make sure base folder exists)
*
*/
virtual void SetFilePath( const std::string& sFilePath ) = 0;
}; };
#endif // INCLUDE_WATCHER_ITA_BUFFERED_AUDIO_FILE_WRITER #endif // INCLUDE_WATCHER_ITA_BUFFERED_AUDIO_FILE_WRITER
...@@ -12,71 +12,78 @@ ...@@ -12,71 +12,78 @@
class ITABufferedAudiofileWriterImpl : public ITABufferedAudiofileWriter class ITABufferedAudiofileWriterImpl : public ITABufferedAudiofileWriter
{ {
public: public:
inline ITABufferedAudiofileWriterImpl( const std::string& sFilePath, inline ITABufferedAudiofileWriterImpl( const ITAAudiofileProperties& props, double dInitialBufferSizeSeconds, double dGrowBufferSizeSeconds )
const ITAAudiofileProperties& props,
double dInitialBufferSizeSeconds,
double dGrowBufferSizeSeconds )
: m_pWriter( NULL ) : m_pWriter( NULL )
, m_oProps( props )
{ {
// Zunächst versuchen den regulären (ungepufferten) Schreiber aufzusetzen
m_pWriter = ITAAudiofileWriter::create( sFilePath, props );
// Initialen Chunk anlegen // Initialen Chunk anlegen
m_iInitialBufferSizeSamples = (int) ceil( dInitialBufferSizeSeconds*props.dSampleRate ); m_iInitialBufferSizeSamples = ( int ) ceil( dInitialBufferSizeSeconds*props.dSampleRate );
m_iGrowBufferSizeSamples = (int) ceil( dGrowBufferSizeSeconds*props.dSampleRate ); m_iGrowBufferSizeSamples = ( int ) ceil( dGrowBufferSizeSeconds*props.dSampleRate );
m_lpChunks.push_back( new Chunk( (int) props.iChannels, m_iInitialBufferSizeSamples ) ); m_lpChunks.push_back( new Chunk( ( int ) props.iChannels, m_iInitialBufferSizeSamples ) );
} };
inline virtual ~ITABufferedAudiofileWriterImpl() inline virtual ~ITABufferedAudiofileWriterImpl()
{ {
// Alle Chunks schreiben und freigeben // Alle Chunks schreiben und freigeben
for (std::list<Chunk*>::iterator it=m_lpChunks.begin(); it!=m_lpChunks.end(); ++it) { for( std::list<Chunk*>::iterator it = m_lpChunks.begin(); it != m_lpChunks.end(); ++it ) {
Chunk* pChunk = (*it); Chunk* pChunk = ( *it );
if (m_pWriter && (pChunk->m_iTail > 0)) if( m_pWriter && ( pChunk->m_iTail > 0 ) )
m_pWriter->write(pChunk->m_iTail, pChunk->m_vpfData); m_pWriter->write( pChunk->m_iTail, pChunk->m_vpfData );
delete pChunk; delete pChunk;
} }
// Schreiber freigeben // Schreiber freigeben
delete m_pWriter; delete m_pWriter;
} };
inline void SetFilePath( const std::string& sFilePath )
{
delete m_pWriter;
m_pWriter = ITAAudiofileWriter::create( sFilePath, m_oProps );
m_sFilePath = sFilePath;
};
inline std::string GetFilePath() const
{
return m_sFilePath;
};
inline virtual void write( int iLength, std::vector<const float*> vpfSource ) inline virtual void write( int iLength, std::vector<const float*> vpfSource )
{ {
// Korrekte Anzahl Kanäle // Korrekte Anzahl Kanäle
int iChannels = m_lpChunks.back()->m_sfSamples.channels(); int iChannels = m_lpChunks.back()->m_sfSamples.channels();
if ((int) vpfSource.size() != iChannels) if( ( int ) vpfSource.size() != iChannels )
ITA_EXCEPT1(INVALID_PARAMETER, "Wrong number of channels in source data"); ITA_EXCEPT1( INVALID_PARAMETER, "Wrong number of channels in source data" );
if( iLength == 0 ) return; if( iLength == 0 ) return;
int iWritten = 0; int iWritten = 0;
int iTotal = iLength; int iTotal = iLength;
int iRemain = iTotal; int iRemain = iTotal;
while (iWritten < iTotal) { while( iWritten < iTotal ) {
Chunk* pTailChunk = m_lpChunks.back(); Chunk* pTailChunk = m_lpChunks.back();
// Soviel in diesen Chunk schreiben wie möglich // Soviel in diesen Chunk schreiben wie möglich
int iChunkRemain = pTailChunk->m_sfSamples.length() - pTailChunk->m_iTail; int iChunkRemain = pTailChunk->m_sfSamples.length() - pTailChunk->m_iTail;
int iCount = std::min( iRemain, iChunkRemain ); int iCount = std::min( iRemain, iChunkRemain );
for (int i=0; i<iChannels; i++) for( int i = 0; i < iChannels; i++ )
pTailChunk->m_sfSamples[i].write( vpfSource[i], iCount, pTailChunk->m_iTail ); pTailChunk->m_sfSamples[ i ].write( vpfSource[ i ], iCount, pTailChunk->m_iTail );
pTailChunk->m_iTail += iCount; pTailChunk->m_iTail += iCount;
iWritten += iCount; iWritten += iCount;
iRemain = iTotal - iWritten; iRemain = iTotal - iWritten;
// Neuen Chunk anlegen, falls noch Daten zu schreiben ... // Neuen Chunk anlegen, falls noch Daten zu schreiben ...
if (iRemain > 0) { if( iRemain > 0 ) {
m_lpChunks.push_back( new Chunk( iChannels, m_iGrowBufferSizeSamples) ); m_lpChunks.push_back( new Chunk( iChannels, m_iGrowBufferSizeSamples ) );
} }
} }
} };
private: private:
// Interner Speicherblock für Samples // Interner Speicherblock für Samples
...@@ -88,26 +95,31 @@ private: ...@@ -88,26 +95,31 @@ private:
int m_iTail; int m_iTail;
inline Chunk( int iChannels, int iCapacity ) inline Chunk( int iChannels, int iCapacity )
: m_sfSamples( iChannels, iCapacity, false ) : m_sfSamples( iChannels, iCapacity, false )
, m_vpfData(iChannels) , m_vpfData( iChannels )
, m_iTail(0) , m_iTail( 0 )
{ {
for( int i=0; i<iChannels; i++ ) for( int i = 0; i < iChannels; i++ )
m_vpfData[i] = m_sfSamples[i].GetData(); m_vpfData[ i ] = m_sfSamples[ i ].GetData();
} }
}; };
ITAAudiofileWriter* m_pWriter; ITAAudiofileWriter* m_pWriter;
std::string m_sFilePath;
std::list<Chunk*> m_lpChunks; std::list<Chunk*> m_lpChunks;
int m_iInitialBufferSizeSamples; int m_iInitialBufferSizeSamples;
int m_iGrowBufferSizeSamples; int m_iGrowBufferSizeSamples;
const ITAAudiofileProperties m_oProps;
//! Copy protection
inline ITABufferedAudiofileWriterImpl& operator=( ITABufferedAudiofileWriterImpl& )
{
ITA_EXCEPT_NOT_IMPLEMENTED;
};
}; };
ITABufferedAudiofileWriter* ITABufferedAudiofileWriter::create(const std::string& sFilePath, ITABufferedAudiofileWriter* ITABufferedAudiofileWriter::create( const ITAAudiofileProperties& props, double dInitialBufferSizeSeconds, double dGrowBufferSizeSeconds )
const ITAAudiofileProperties& props,
double dInitialBufferSizeSeconds,
double dGrowBufferSizeSeconds)
{ {
return new ITABufferedAudiofileWriterImpl( sFilePath, props, dInitialBufferSizeSeconds, dGrowBufferSizeSeconds ); return new ITABufferedAudiofileWriterImpl( props, dInitialBufferSizeSeconds, dGrowBufferSizeSeconds );
} }
...@@ -33,7 +33,8 @@ bool INIFileKeyExists( const std::string& sINIFilename, const std::string& sSect ...@@ -33,7 +33,8 @@ bool INIFileKeyExists( const std::string& sINIFilename, const std::string& sSect
return false; return false;
} }
void INIFileUseFile( const std::string& sINIFilename ) { void INIFileUseFile( const std::string& sINIFilename )
{
// Sicherstellen das die INI-Datei existiert // Sicherstellen das die INI-Datei existiert
// [fwe 2008-11-07] Bugfix, baby! Das geht beim reinen Schreiben nicht: INIFileRequireINIFile(sINIFilename); // [fwe 2008-11-07] Bugfix, baby! Das geht beim reinen Schreiben nicht: INIFileRequireINIFile(sINIFilename);
...@@ -478,11 +479,13 @@ bool INIFileWriteStringList( const std::string& sINIFilename, ...@@ -478,11 +479,13 @@ bool INIFileWriteStringList( const std::string& sINIFilename,
* | | * | |
* +-----------------------------------------------------------------------------------------+ */ * +-----------------------------------------------------------------------------------------+ */
bool INIFileSectionExists( const std::string& sSection ) { bool INIFileSectionExists( const std::string& sSection )
{
return INIFileSectionExists( sCurrentINIFile, sSection ); return INIFileSectionExists( sCurrentINIFile, sSection );
} }
std::vector<std::string> INIFileGetSections() { std::vector<std::string> INIFileGetSections()
{
return INIFileGetSections( sCurrentINIFile ); return INIFileGetSections( sCurrentINIFile );
} }
...@@ -530,39 +533,48 @@ bool INIFileReadBool( const std::string& sKey, bool bDefaultValue ) { ...@@ -530,39 +533,48 @@ bool INIFileReadBool( const std::string& sKey, bool bDefaultValue ) {
return INIFileReadBool( sCurrentINIFile, sCurrentSection, sKey, bDefaultValue ); return INIFileReadBool( sCurrentINIFile, sCurrentSection, sKey, bDefaultValue );
} }
std::string INIFileReadString( const std::string& sKey, std::string sDefaultValue ) { std::string INIFileReadString( const std::string& sKey, std::string sDefaultValue )
{
return INIFileReadString( sCurrentINIFile, sCurrentSection, sKey, sDefaultValue ); return INIFileReadString( sCurrentINIFile, sCurrentSection, sKey, sDefaultValue );
} }
std::vector<int> INIFileReadIntList( const std::string& sKey, char cSeparator ) { std::vector<int> INIFileReadIntList( const std::string& sKey, char cSeparator )
{
return INIFileReadIntList( sCurrentINIFile, sCurrentSection, sKey, cSeparator ); return INIFileReadIntList( sCurrentINIFile, sCurrentSection, sKey, cSeparator );
} }
std::vector<unsigned int> INIFileReadUIntList( const std::string& sKey, char cSeparator ) { std::vector<unsigned int> INIFileReadUIntList( const std::string& sKey, char cSeparator )
{
return INIFileReadUIntList( sCurrentINIFile, sCurrentSection, sKey, cSeparator ); return INIFileReadUIntList( sCurrentINIFile, sCurrentSection, sKey, cSeparator );
} }
std::vector<float> INIFileReadFloatList( const std::string& sKey, char cSeparator ) { std::vector<float> INIFileReadFloatList( const std::string& sKey, char cSeparator )
{
return INIFileReadFloatList( sCurrentINIFile, sCurrentSection, sKey, cSeparator ); return INIFileReadFloatList( sCurrentINIFile, sCurrentSection, sKey, cSeparator );
} }
std::vector<double> INIFileReadDoubleList( const std::string& sKey, char cSeparator ) { std::vector<double> INIFileReadDoubleList( const std::string& sKey, char cSeparator )
{
return INIFileReadDoubleList( sCurrentINIFile, sCurrentSection, sKey, cSeparator ); return INIFileReadDoubleList( sCurrentINIFile, sCurrentSection, sKey, cSeparator );
} }
std::vector<std::string> INIFileReadStringList( const std::string& sKey, char cSeparator ) { std::vector<std::string> INIFileReadStringList( const std::string& sKey, char cSeparator )
{
return INIFileReadStringList( sCurrentINIFile, sCurrentSection, sKey, cSeparator ); return INIFileReadStringList( sCurrentINIFile, sCurrentSection, sKey, cSeparator );
} }
int INIFileReadIntExplicit( const std::string& sKey ) { int INIFileReadIntExplicit( const std::string& sKey )
{
return INIFileReadIntExplicit( sCurrentINIFile, sCurrentSection, sKey ); return INIFileReadIntExplicit( sCurrentINIFile, sCurrentSection, sKey );
} }
unsigned int INIFileReadUIntExplicit( const std::string& sKey ) { unsigned int INIFileReadUIntExplicit( const std::string& sKey )
{
return INIFileReadUIntExplicit( sCurrentINIFile, sCurrentSection, sKey ); return INIFileReadUIntExplicit( sCurrentINIFile, sCurrentSection, sKey );
} }
long INIFileReadLongExplicit( const std::string& sKey ) { long INIFileReadLongExplicit( const std::string& sKey )
{
return INIFileReadLongExplicit( sCurrentINIFile, sCurrentSection, sKey ); return INIFileReadLongExplicit( sCurrentINIFile, sCurrentSection, sKey );
} }
......
...@@ -25,85 +25,92 @@ std::string FixPath( const std::string& sPath ) ...@@ -25,85 +25,92 @@ std::string FixPath( const std::string& sPath )
return std::string( "." ) + PATH_SEPARATOR + sPath; return std::string( "." ) + PATH_SEPARATOR + sPath;
} }
std::vector<std::string> INIFileGetSections(const std::string& sINIFilename) { std::vector<std::string> INIFileGetSections( const std::string& sINIFilename )
{
// [fwe: Bugfix 2008-09-09] Sicherstellen das die Datei berhaupt existiert // [fwe: Bugfix 2008-09-09] Sicherstellen das die Datei berhaupt existiert
INIFileRequireINIFile(sINIFilename); INIFileRequireINIFile( sINIFilename );
// fwe: Insgesamt 64k Zeichen fr die Liste der Sektionsnamen // fwe: Insgesamt 64k Zeichen fr die Liste der Sektionsnamen
// sollte fr die meisten Anwendungen reichen // sollte fr die meisten Anwendungen reichen
const unsigned int SECTION_NAME_BUFFER_SIZE = 65536; const unsigned int SECTION_NAME_BUFFER_SIZE = 65536;
char buf[SECTION_NAME_BUFFER_SIZE]; char buf[ SECTION_NAME_BUFFER_SIZE ];
std::vector<std::string> vsResult; std::vector<std::string> vsResult;
if (GetPrivateProfileSectionNamesA(buf, SECTION_NAME_BUFFER_SIZE, FixPath(sINIFilename).c_str()) > 0) { if( GetPrivateProfileSectionNamesA( buf, SECTION_NAME_BUFFER_SIZE, FixPath( sINIFilename ).c_str() ) > 0 )
{
char* p = buf; char* p = buf;
unsigned int l; unsigned int l;
while ((l = (unsigned int) strlen(p)) > 0) { while( ( l = ( unsigned int ) strlen( p ) ) > 0 ) {
vsResult.push_back(p); vsResult.push_back( p );
p += l+1; p += l + 1;
} }
} }
return vsResult; return vsResult;
} }
std::vector<std::string> INIFileGetKeys(const std::string& sINIFilename, const std::string& sSection) { std::vector<std::string> INIFileGetKeys( const std::string& sINIFilename, const std::string& sSection )
{
// [fwe: Bugfix 2008-09-09] Sicherstellen das die Datei berhaupt existiert // [fwe: Bugfix 2008-09-09] Sicherstellen das die Datei berhaupt existiert
INIFileRequireINIFile(sINIFilename); INIFileRequireINIFile( sINIFilename );
// fwe: Insgesamt 64k Zeichen fr die Liste der Sektionsnamen // fwe: Insgesamt 64k Zeichen fr die Liste der Sektionsnamen
// sollte fr die meisten Anwendungen reichen // sollte fr die meisten Anwendungen reichen
const unsigned int SECTION_BUFFER_SIZE = 65536; const unsigned int SECTION_BUFFER_SIZE = 65536;
char buf[SECTION_BUFFER_SIZE]; char buf[ SECTION_BUFFER_SIZE ];
std::vector<std::string> vsResult; std::vector<std::string> vsResult;
if (GetPrivateProfileSectionA(sSection.c_str(), buf, SECTION_BUFFER_SIZE, FixPath(sINIFilename).c_str()) > 0) { if( GetPrivateProfileSectionA( sSection.c_str(), buf, SECTION_BUFFER_SIZE, FixPath( sINIFilename ).c_str() ) > 0 )
{
char* p = buf; char* p = buf;
unsigned int l; unsigned int l;
while ((l = (unsigned int) strlen(p)) > 0) { while( ( l = ( unsigned int ) strlen( p ) ) > 0 )
{
std::string s = p; std::string s = p;
// Windows macht einen Fehler und gibt hier auch auskommentierte Schlssel zurck. Deshalb Filtern: // Windows macht einen Fehler und gibt hier auch auskommentierte Schlssel zurck. Deshalb Filtern:
if (s[0] != '#') { if( s[ 0 ] != '#' ) {
// Gleichheitszeichen suchen // Gleichheitszeichen suchen
std::string t = s.substr(0, s.find_first_of('=')); std::string t = s.substr( 0, s.find_first_of( '=' ) );
if (!t.empty()) vsResult.push_back(t); if( !t.empty() ) vsResult.push_back( t );
} }
p += l+1; p += l + 1;
} }
} }
return vsResult; return vsResult;
} }
std::string INIFileReadString(const std::string& sINIFilename, const std::string& sSection, const std::string& sKey, std::string sDefaultValue) { std::string INIFileReadString( const std::string& sINIFilename, const std::string& sSection, const std::string& sKey, std::string sDefaultValue )
{
// Sicherstellen das die INI-Datei existiert // Sicherstellen das die INI-Datei existiert
INIFileRequireINIFile(sINIFilename); INIFileRequireINIFile( sINIFilename );
// Zeichenpuffer // Zeichenpuffer
char buf[MAX_VALUE_STRING_LENGTH]; char buf[ MAX_VALUE_STRING_LENGTH ];
GetPrivateProfileStringA(sSection.c_str(), GetPrivateProfileStringA( sSection.c_str(),
sKey.c_str(), sKey.c_str(),
sDefaultValue.c_str(), sDefaultValue.c_str(),
(LPSTR) buf, ( LPSTR ) buf,
(DWORD) MAX_VALUE_STRING_LENGTH, ( DWORD ) MAX_VALUE_STRING_LENGTH,
FixPath(sINIFilename).c_str()); FixPath( sINIFilename ).c_str() );
return std::string(buf); return std::string( buf );
} }
bool INIFileWriteString(const std::string& sINIFilename, const std::string& sSection, const std::string& sKey, const std::string& sValue) { bool INIFileWriteString( const std::string& sINIFilename, const std::string& sSection, const std::string& sKey, const std::string& sValue )
{
// [fwe 2011-06-14] Improvement: Put a whitespace after the = in the file. Looks much nicer ;-) // [fwe 2011-06-14] Improvement: Put a whitespace after the = in the file. Looks much nicer ;-)
std::string s(" "); std::string s( " " );
s.append(sValue); s.append( sValue );
return (WritePrivateProfileStringA(sSection.c_str(), return ( WritePrivateProfileStringA( sSection.c_str(),
sKey.c_str(), sKey.c_str(),
s.c_str(), s.c_str(),
FixPath(sINIFilename).c_str()) == TRUE); FixPath( sINIFilename ).c_str() ) == TRUE );
} }
#endif // _WIN32 #endif // _WIN32
......
...@@ -17,6 +17,16 @@ vista_create_default_info_file( ITAStringUtilsTest ) ...@@ -17,6 +17,16 @@ vista_create_default_info_file( ITAStringUtilsTest )
set_property( TARGET ITAStringUtilsTest PROPERTY FOLDER "ITACoreLibs/Tests/ITABase" ) set_property( TARGET ITAStringUtilsTest PROPERTY FOLDER "ITACoreLibs/Tests/ITABase" )
add_executable( ConfigUtilsTest ConfigUtilsTest.cpp )
target_link_libraries( ConfigUtilsTest ${VISTA_USE_PACKAGE_LIBRARIES} )
vista_configure_app( ConfigUtilsTest )
vista_install( ConfigUtilsTest )
vista_create_default_info_file( ConfigUtilsTest )
set_property( TARGET ConfigUtilsTest PROPERTY FOLDER "ITACoreLibs/Tests/ITABase" )
add_executable( ITABaseSampleBufferTest ITABaseSampleBufferTest.cpp ) add_executable( ITABaseSampleBufferTest ITABaseSampleBufferTest.cpp )
target_link_libraries( ITABaseSampleBufferTest ${VISTA_USE_PACKAGE_LIBRARIES} ) target_link_libraries( ITABaseSampleBufferTest ${VISTA_USE_PACKAGE_LIBRARIES} )
......
#include <ITAConfigUtils.h>
#include <iostream>
using namespace std;
int main( int nArgsIn, char** pccArgs )
{
if( nArgsIn > 1 )
INIFileUseFile( std::string( pccArgs[ 1 ] ) );
else
INIFileUseFile( "ConfigUtilsTest.ini" );
auto sections = INIFileGetSections();
for( auto section : sections )
{
cout << section << endl;
INIFileUseSection( section );
auto keys = INIFileGetKeys( section );
for( auto key : keys )
cout << " + " << key << "\t'" << INIFileReadString( key ) << "' [STRING] " << endl;
}
return 0;
}
#
# ConfigUtilsTest
#
[ff]
enabled1 = true
enabled2 = 1
enabled3 = false
[a:b]
enabled = true
[a:c]
enabled = false
[d:x]
enabled = true
[dd]
enabled = true
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment