2018-02-19 01:25:43 -03:00
/*
* libopenmpt_example_cxx . cpp
* - - - - - - - - - - - - - - - - - - - - - - - - - -
* Purpose : libopenmpt C + + API example
* Notes : PortAudio C + + is used for sound output .
* Authors : OpenMPT Devs
* The OpenMPT source code is released under the BSD license . Read LICENSE for more details .
*/
/*
* Usage : libopenmpt_example_cxx SOMEMODULE
*/
# include <exception>
# include <fstream>
# include <iostream>
# include <new>
# include <stdexcept>
# include <vector>
# include <libopenmpt/libopenmpt.hpp>
2021-12-26 08:29:43 -03:00
# if defined( __clang__ )
# if ( ( __clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__ ) >= 40000 )
2019-10-24 21:33:28 -03:00
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-dynamic-exception-spec"
# endif
# endif
2018-02-19 01:25:43 -03:00
# include <portaudiocpp/PortAudioCpp.hxx>
2021-12-26 08:29:43 -03:00
# if defined( __clang__ )
# if ( ( __clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__ ) >= 40000 )
2019-10-24 21:33:28 -03:00
# pragma clang diagnostic pop
# endif
# endif
2018-02-19 01:25:43 -03:00
# if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
# if defined( __GNUC__ )
// mingw-w64 g++ does only default to special C linkage for "main", but not for "wmain" (see <https://sourceforge.net/p/mingw-w64/wiki2/Unicode%20apps/>).
extern " C " int wmain ( int argc , wchar_t * argv [ ] ) {
# else
int wmain ( int argc , wchar_t * argv [ ] ) {
# endif
# else
int main ( int argc , char * argv [ ] ) {
# endif
try {
if ( argc ! = 2 ) {
throw std : : runtime_error ( " Usage: libopenmpt_example_cxx SOMEMODULE " ) ;
}
2020-09-22 01:54:24 -03:00
constexpr std : : size_t buffersize = 480 ;
constexpr std : : int32_t samplerate = 48000 ;
2018-02-19 01:25:43 -03:00
std : : ifstream file ( argv [ 1 ] , std : : ios : : binary ) ;
openmpt : : module mod ( file ) ;
portaudio : : AutoSystem portaudio_initializer ;
portaudio : : System & portaudio = portaudio : : System : : instance ( ) ;
2020-09-22 01:54:24 -03:00
std : : vector < float > left ( buffersize ) ;
std : : vector < float > right ( buffersize ) ;
std : : vector < float > interleaved_buffer ( buffersize * 2 ) ;
bool is_interleaved = false ;
2021-12-26 08:29:43 -03:00
# if defined( _MSC_VER ) && defined( _PREFAST_ )
2020-09-22 01:54:24 -03:00
// work-around bug in VS2019 MSVC 16.5.5 static analyzer
is_interleaved = false ;
2018-02-19 01:25:43 -03:00
portaudio : : DirectionSpecificStreamParameters outputstream_parameters ( portaudio . defaultOutputDevice ( ) , 2 , portaudio : : FLOAT32 , false , portaudio . defaultOutputDevice ( ) . defaultHighOutputLatency ( ) , 0 ) ;
portaudio : : StreamParameters stream_parameters ( portaudio : : DirectionSpecificStreamParameters : : null ( ) , outputstream_parameters , samplerate , paFramesPerBufferUnspecified , paNoFlag ) ;
portaudio : : BlockingStream stream ( stream_parameters ) ;
2020-09-22 01:54:24 -03:00
# else
portaudio : : BlockingStream stream = [ & ] ( ) {
try {
is_interleaved = false ;
portaudio : : DirectionSpecificStreamParameters outputstream_parameters ( portaudio . defaultOutputDevice ( ) , 2 , portaudio : : FLOAT32 , false , portaudio . defaultOutputDevice ( ) . defaultHighOutputLatency ( ) , 0 ) ;
portaudio : : StreamParameters stream_parameters ( portaudio : : DirectionSpecificStreamParameters : : null ( ) , outputstream_parameters , samplerate , paFramesPerBufferUnspecified , paNoFlag ) ;
return portaudio : : BlockingStream ( stream_parameters ) ;
} catch ( const portaudio : : PaException & e ) {
if ( e . paError ( ) ! = paSampleFormatNotSupported ) {
throw ;
}
is_interleaved = true ;
portaudio : : DirectionSpecificStreamParameters outputstream_parameters ( portaudio . defaultOutputDevice ( ) , 2 , portaudio : : FLOAT32 , true , portaudio . defaultOutputDevice ( ) . defaultHighOutputLatency ( ) , 0 ) ;
portaudio : : StreamParameters stream_parameters ( portaudio : : DirectionSpecificStreamParameters : : null ( ) , outputstream_parameters , samplerate , paFramesPerBufferUnspecified , paNoFlag ) ;
return portaudio : : BlockingStream ( stream_parameters ) ;
}
} ( ) ;
# endif
2018-02-19 01:25:43 -03:00
stream . start ( ) ;
while ( true ) {
2020-09-22 01:54:24 -03:00
std : : size_t count = is_interleaved ? mod . read_interleaved_stereo ( samplerate , buffersize , interleaved_buffer . data ( ) ) : mod . read ( samplerate , buffersize , left . data ( ) , right . data ( ) ) ;
2018-02-19 01:25:43 -03:00
if ( count = = 0 ) {
break ;
}
try {
2020-09-22 01:54:24 -03:00
if ( is_interleaved ) {
stream . write ( interleaved_buffer . data ( ) , static_cast < unsigned long > ( count ) ) ;
} else {
const float * const buffers [ 2 ] = { left . data ( ) , right . data ( ) } ;
stream . write ( buffers , static_cast < unsigned long > ( count ) ) ;
}
2018-02-19 01:25:43 -03:00
} catch ( const portaudio : : PaException & pa_exception ) {
if ( pa_exception . paError ( ) ! = paOutputUnderflowed ) {
throw ;
}
}
}
stream . stop ( ) ;
} catch ( const std : : bad_alloc & ) {
std : : cerr < < " Error: " < < std : : string ( " out of memory " ) < < std : : endl ;
return 1 ;
} catch ( const std : : exception & e ) {
std : : cerr < < " Error: " < < std : : string ( e . what ( ) ? e . what ( ) : " unknown error " ) < < std : : endl ;
return 1 ;
}
return 0 ;
}