libopenmpt 0.5.0-pre.5+r11801 cross-platform C++ and C library to decode tracked music files

C API

# Error Handling

- Functions with no return value in the corresponding C++ API return 0 on failure and 1 on success.
- Functions that return a string in the corresponding C++ API return a dynamically allocated const char *. In case of failure or memory allocation failure, a NULL pointer is returned.
- Functions that return integer values signal error condition by returning an invalid value (-1 in most cases, 0 in some cases).
- All functions that work on an openmpt_module object will call an openmpt_error_func and depending on the value returned by this function log the error code and/xor/or store it inside the openmpt_module object. Stored error codes can be accessed with the openmpt_module_error_get_last() and openmpt_module_error_get_last_message(). Stored errors will not get cleared automatically and should be reset with openmpt_module_error_clear().
- Some functions not directly related to an openmpt_module object take an explicit openmpt_error_func error function callback and a pointer to an int and behave analog to the functions working on an openmpt_module object.

# Strings

- All strings returned from libopenmpt are encoded in UTF-8.
- All strings passed to libopenmpt should also be encoded in UTF-8. Behaviour in case of invalid UTF-8 is unspecified.
- libopenmpt does not enforce or expect any particular Unicode normalization form.
- All strings returned from libopenmpt are dynamically allocated and must be freed with openmpt_free_string(). Do NOT use the C standard library free() for libopenmpt strings as that would make your code invalid on windows when dynamically linking against libopenmpt which itself statically links to the C runtime.
- All strings passed to libopenmpt are copied. No ownership is assumed or transferred.

# File I/O

libopenmpt can use 3 different strategies for file I/O.

- openmpt_module_create_from_memory2() will load the module from the provided memory buffer, which will require loading all data upfront by the library caller.
- openmpt_module_create2() with a seekable stream will load the module via callbacks to the stream interface. libopenmpt will not implement an additional buffering layer in this case which means the callbacks are assumed to be performant even with small i/o sizes.
- openmpt_module_create2() with an unseekable stream will load the module via callbacks to the stream interface. libopempt will make an internal copy as it goes along, and sometimes have to pre-cache the whole file in case it needs to know the complete file size. This strategy is intended to be used if the file is located on a high latency network.

create function | speed | memory consumption
--- | --- | ---
openmpt_module_create_from_memory2() | fast | medium
openmpt_module_create2() with seekable stream | slow | low
openmpt_module_create2() with unseekable stream | medium | high

In all cases, the data or stream passed to the create function is no longer needed after the openmpt_module has been created and can be freed by the caller.

# Output Format

libopenmpt supports a wide range of PCM output formats: [8000..192000]/[mono|stereo|quad]/[f32|i16].

Unless you have some very specific requirements demanding a particular aspect of the output format, you should always prefer 48000/stereo/f32 as the libopenmpt PCM format.

- Please prefer 48000Hz unless the user explicitly demands something else. Practically all audio equipment and file formats use 48000Hz nowadays.
- Practically all module formats are made for stereo output. Mono will not give you any measurable speed improvements and can trivially be obtained from the stereo output anyway. Quad is not expected by almost all modules and even if they do use surround effects, they expect the effects to be mixed to stereo.
- Floating point output provides headroom instead of hard clipping if the module is louder than 0dBFs, will give you a better signal-to-noise ratio than int16 output, and avoid the need to apply an additional dithering to the output by libopenmpt. Unless your platform has no floating point unit at all, floating point will thus also be slightly faster.

# libopenmpt in multi-threaded environments

- libopenmpt is thread-aware.
- Individual libopenmpt objects are not thread-safe.
- libopenmpt itself does not spawn any user-visible threads but may spawn threads for internal use.
- You must ensure to only ever access a particular libopenmpt object from a single thread at a time.
- Consecutive accesses can happen from different threads.
- Different objects can be accessed concurrently from different threads.

# Statically linking to libopenmpt

libopenmpt is implemented in C++. This implies that linking to libopenmpt statically requires linking to the C++ runtime and standard library. The highly preferred and recommended way to do this is by using the C++ compiler instead of the platform linker to do the linking. This will do all necessary things that are C++ specific (in particular, it will pull in the appropriate runtime and/or library). If for whatever reason it is not possible to use the C++ compiler for statically linking against libopenmpt, the libopenmpt build system can list the required libraries in the pkg-config file `libopenmpt.pc`. However, there is no reliable way to determine the name of the required library or libraries from within the build system. The libopenmpt autotools `configure` and plain `Makefile` honor the custom variable `CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing the standard library (or libraries) required for static linking. The contents of this variable will be put in `libopenmpt.pc` `Libs.private` and used for nothing else.

This problem is inherent to libraries implemented in C++ that can also be used without a C++ compiler. Other libraries try to solve that by listing `-lstdc++` unconditionally in `Libs.private`. However, that will break platforms that use a different C++ standard library (in particular FreeBSD).

See https://lists.freedesktop.org/archives/pkg-config/2016-August/001055.html .

Dymically linking to libopenmpt does not require anything special and will work as usual (and exactly as done for libraries implemented in C).

Note: This section does not apply when using Microsoft Visual Studio or Andriod NDK ndk-build build systems.

# Detailed documentation

libopenmpt C

In case a function is not documented here, you might want to look at the libopenmpt C++ documentation. The C and C++ APIs are kept semantically as close as possible.

# Examples

## Unsafe, simplified example without any error checking to get a first idea of the API

/*
* libopenmpt_example_c_unsafe.c
* -----------------------------
* Purpose: libopenmpt C API simplified example
* Notes : PortAudio 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_c_unsafe SOMEMODULE
* CAUTION: This simple example does no error cheking at all.
*/
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libopenmpt/libopenmpt.h>
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#include <portaudio.h>
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static int16_t left[BUFFERSIZE];
static int16_t right[BUFFERSIZE];
static int16_t * const buffers[2] = { left, right };
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
FILE * file = 0;
openmpt_module * mod = 0;
size_t count = 0;
PaStream * stream = 0;
(void)argc;
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
file = _wfopen( argv[1], L"rb" );
#else
file = fopen( argv[1], "rb" );
#endif
mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
fclose( file );
Pa_Initialize();
Pa_OpenDefaultStream( &stream, 0, 2, paInt16 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
Pa_StartStream( stream );
while ( 1 ) {
count = openmpt_module_read_stereo( mod, SAMPLERATE, BUFFERSIZE, left, right );
if ( count == 0 ) {
break;
}
Pa_WriteStream( stream, buffers, (unsigned long)count );
}
Pa_StopStream( stream );
Pa_CloseStream( stream );
Pa_Terminate();
openmpt_module_destroy( mod );
return 0;
}

## FILE*

/*
* libopenmpt_example_c.c
* ----------------------
* Purpose: libopenmpt C API example
* Notes : PortAudio 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_c SOMEMODULE
*/
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libopenmpt/libopenmpt.h>
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#include <portaudio.h>
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static int16_t left[BUFFERSIZE];
static int16_t right[BUFFERSIZE];
static int16_t * const buffers[2] = { left, right };
static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
(void)userdata;
if ( message ) {
fprintf( stderr, "openmpt: %s\n", message );
}
}
static int libopenmpt_example_errfunc( int error, void * userdata ) {
(void)userdata;
(void)error;
return OPENMPT_ERROR_FUNC_RESULT_DEFAULT & ~OPENMPT_ERROR_FUNC_RESULT_LOG;
}
static void libopenmpt_example_print_error( const char * func_name, int mod_err, const char * mod_err_str ) {
if ( !func_name ) {
func_name = "unknown function";
}
if ( mod_err == OPENMPT_ERROR_OUT_OF_MEMORY ) {
mod_err_str = openmpt_error_string( mod_err );
if ( !mod_err_str ) {
fprintf( stderr, "Error: %s\n", "OPENMPT_ERROR_OUT_OF_MEMORY" );
} else {
fprintf( stderr, "Error: %s\n", mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
} else {
if ( !mod_err_str ) {
mod_err_str = openmpt_error_string( mod_err );
if ( !mod_err_str ) {
fprintf( stderr, "Error: %s failed.\n", func_name );
} else {
fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
}
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
}
}
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
int result = 0;
FILE * file = 0;
openmpt_module * mod = 0;
int mod_err = OPENMPT_ERROR_OK;
const char * mod_err_str = NULL;
size_t count = 0;
PaError pa_error = paNoError;
int pa_initialized = 0;
PaStream * stream = 0;
if ( argc != 2 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c SOMEMODULE'." );
goto fail;
}
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
if ( wcslen( argv[1] ) == 0 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c SOMEMODULE'." );
goto fail;
}
file = _wfopen( argv[1], L"rb" );
#else
if ( strlen( argv[1] ) == 0 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c SOMEMODULE'." );
goto fail;
}
file = fopen( argv[1], "rb" );
#endif
if ( !file ) {
fprintf( stderr, "Error: %s\n", "fopen() failed." );
goto fail;
}
mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
if ( !mod ) {
libopenmpt_example_print_error( "openmpt_module_create2()", mod_err, mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
goto fail;
}
openmpt_module_set_error_func( mod, NULL, NULL );
pa_error = Pa_Initialize();
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_Initialize() failed." );
goto fail;
}
pa_initialized = 1;
pa_error = Pa_OpenDefaultStream( &stream, 0, 2, paInt16 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_OpenStream() failed." );
goto fail;
}
if ( !stream ) {
fprintf( stderr, "Error: %s\n", "Pa_OpenStream() failed." );
goto fail;
}
pa_error = Pa_StartStream( stream );
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_StartStream() failed." );
goto fail;
}
while ( 1 ) {
openmpt_module_error_clear( mod );
count = openmpt_module_read_stereo( mod, SAMPLERATE, BUFFERSIZE, left, right );
mod_err = openmpt_module_error_get_last( mod );
mod_err_str = openmpt_module_error_get_last_message( mod );
if ( mod_err != OPENMPT_ERROR_OK ) {
libopenmpt_example_print_error( "openmpt_module_read_stereo()", mod_err, mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
if ( count == 0 ) {
break;
}
pa_error = Pa_WriteStream( stream, buffers, (unsigned long)count );
if ( pa_error == paOutputUnderflowed ) {
pa_error = paNoError;
}
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_WriteStream() failed." );
goto fail;
}
}
result = 0;
goto cleanup;
fail:
result = 1;
cleanup:
if ( stream ) {
if ( Pa_IsStreamActive( stream ) == 1 ) {
Pa_StopStream( stream );
}
Pa_CloseStream( stream );
stream = 0;
}
if ( pa_initialized ) {
Pa_Terminate();
pa_initialized = 0;
}
if ( mod ) {
openmpt_module_destroy( mod );
mod = 0;
}
if ( file ) {
fclose( file );
file = 0;
}
return result;
}

## in memory

/*
* libopenmpt_example_c_mem.c
* --------------------------
* Purpose: libopenmpt C API example
* Notes : PortAudio 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_c_mem SOMEMODULE
*/
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libopenmpt/libopenmpt.h>
#include <portaudio.h>
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static int16_t left[BUFFERSIZE];
static int16_t right[BUFFERSIZE];
static int16_t * const buffers[2] = { left, right };
static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
(void)userdata;
if ( message ) {
fprintf( stderr, "openmpt: %s\n", message );
}
}
static int libopenmpt_example_errfunc( int error, void * userdata ) {
(void)userdata;
(void)error;
return OPENMPT_ERROR_FUNC_RESULT_DEFAULT & ~OPENMPT_ERROR_FUNC_RESULT_LOG;
}
static void libopenmpt_example_print_error( const char * func_name, int mod_err, const char * mod_err_str ) {
if ( !func_name ) {
func_name = "unknown function";
}
if ( mod_err == OPENMPT_ERROR_OUT_OF_MEMORY ) {
mod_err_str = openmpt_error_string( mod_err );
if ( !mod_err_str ) {
fprintf( stderr, "Error: %s\n", "OPENMPT_ERROR_OUT_OF_MEMORY" );
} else {
fprintf( stderr, "Error: %s\n", mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
} else {
if ( !mod_err_str ) {
mod_err_str = openmpt_error_string( mod_err );
if ( !mod_err_str ) {
fprintf( stderr, "Error: %s failed.\n", func_name );
} else {
fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
}
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
}
}
typedef struct blob_t {
size_t size;
void * data;
} blob_t;
static void free_blob( blob_t * blob ) {
if ( blob ) {
if ( blob->data ) {
free( blob->data );
blob->data = 0;
}
blob->size = 0;
free( blob );
}
}
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
static blob_t * load_file( const wchar_t * filename ) {
#else
static blob_t * load_file( const char * filename ) {
#endif
blob_t * result = 0;
blob_t * blob = 0;
FILE * file = 0;
long tell_result = 0;
blob = malloc( sizeof( blob_t ) );
if ( !blob ) {
goto fail;
}
memset( blob, 0, sizeof( blob_t ) );
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
file = _wfopen( filename, L"rb" );
#else
file = fopen( filename, "rb" );
#endif
if ( !file ) {
goto fail;
}
if ( fseek( file, 0, SEEK_END ) != 0 ) {
goto fail;
}
tell_result = ftell( file );
if ( tell_result < 0 ) {
goto fail;
}
if ( (unsigned long)tell_result > SIZE_MAX ) {
goto fail;
}
blob->size = (size_t)tell_result;
if ( fseek( file, 0, SEEK_SET ) != 0 ) {
goto fail;
}
blob->data = malloc( blob->size );
if ( !blob->data ) {
goto fail;
}
memset( blob->data, 0, blob->size );
if ( fread( blob->data, 1, blob->size, file ) != blob->size ) {
goto fail;
}
result = blob;
blob = 0;
goto cleanup;
fail:
result = 0;
cleanup:
if ( blob ) {
free_blob( blob );
blob = 0;
}
if ( file ) {
fclose( file );
file = 0;
}
return result;
}
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
int result = 0;
blob_t * blob = 0;
openmpt_module * mod = 0;
int mod_err = OPENMPT_ERROR_OK;
const char * mod_err_str = NULL;
size_t count = 0;
PaError pa_error = paNoError;
int pa_initialized = 0;
PaStream * stream = 0;
if ( argc != 2 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_mem SOMEMODULE'." );
goto fail;
}
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
if ( wcslen( argv[1] ) == 0 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_mem SOMEMODULE'." );
goto fail;
}
#else
if ( strlen( argv[1] ) == 0 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_mem SOMEMODULE'." );
goto fail;
}
#endif
blob = load_file( argv[1] );
if ( !blob ) {
fprintf( stderr, "Error: %s\n", "load_file() failed." );
goto fail;
}
mod = openmpt_module_create_from_memory2( blob->data, blob->size, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
if ( !mod ) {
libopenmpt_example_print_error( "openmpt_module_create_from_memory2()", mod_err, mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
goto fail;
}
pa_error = Pa_Initialize();
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_Initialize() failed." );
goto fail;
}
pa_initialized = 1;
pa_error = Pa_OpenDefaultStream( &stream, 0, 2, paInt16 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_OpenStream() failed." );
goto fail;
}
if ( !stream ) {
fprintf( stderr, "Error: %s\n", "Pa_OpenStream() failed." );
goto fail;
}
pa_error = Pa_StartStream( stream );
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_StartStream() failed." );
goto fail;
}
while ( 1 ) {
openmpt_module_error_clear( mod );
count = openmpt_module_read_stereo( mod, SAMPLERATE, BUFFERSIZE, left, right );
mod_err = openmpt_module_error_get_last( mod );
mod_err_str = openmpt_module_error_get_last_message( mod );
if ( mod_err != OPENMPT_ERROR_OK ) {
libopenmpt_example_print_error( "openmpt_module_read_stereo()", mod_err, mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
if ( count == 0 ) {
break;
}
pa_error = Pa_WriteStream( stream, buffers, (unsigned long)count );
if ( pa_error == paOutputUnderflowed ) {
pa_error = paNoError;
}
if ( pa_error != paNoError ) {
fprintf( stderr, "Error: %s\n", "Pa_WriteStream() failed." );
goto fail;
}
}
result = 0;
goto cleanup;
fail:
result = 1;
cleanup:
if ( stream ) {
if ( Pa_IsStreamActive( stream ) == 1 ) {
Pa_StopStream( stream );
}
Pa_CloseStream( stream );
stream = 0;
}
if ( pa_initialized ) {
Pa_Terminate();
pa_initialized = 0;
}
if ( mod ) {
openmpt_module_destroy( mod );
mod = 0;
}
if ( blob ) {
free_blob( blob );
blob = 0;
}
return result;
}

## reading FILE* and writing PCM data to STDOUT (usable without PortAudio)

/*
* libopenmpt_example_c_stdout.c
* -----------------------------
* Purpose: libopenmpt C API simple example
* Notes : This example writes raw 48000Hz / stereo / 16bit native endian PCM data to stdout.
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
/*
* Usage: libopenmpt_example_c_stdout SOMEMODULE | aplay --file-type raw --format=dat
*/
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <libopenmpt/libopenmpt.h>
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
(void)userdata;
if ( message ) {
fprintf( stderr, "openmpt: %s\n", message );
}
}
static int libopenmpt_example_errfunc( int error, void * userdata ) {
(void)userdata;
(void)error;
return OPENMPT_ERROR_FUNC_RESULT_DEFAULT & ~OPENMPT_ERROR_FUNC_RESULT_LOG;
}
static void libopenmpt_example_print_error( const char * func_name, int mod_err, const char * mod_err_str ) {
if ( !func_name ) {
func_name = "unknown function";
}
if ( mod_err == OPENMPT_ERROR_OUT_OF_MEMORY ) {
mod_err_str = openmpt_error_string( mod_err );
if ( !mod_err_str ) {
fprintf( stderr, "Error: %s\n", "OPENMPT_ERROR_OUT_OF_MEMORY" );
} else {
fprintf( stderr, "Error: %s\n", mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
} else {
if ( !mod_err_str ) {
mod_err_str = openmpt_error_string( mod_err );
if ( !mod_err_str ) {
fprintf( stderr, "Error: %s failed.\n", func_name );
} else {
fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
}
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
}
}
static ssize_t xwrite( int fd, const void * buffer, size_t size ) {
size_t written = 0;
ssize_t retval = 0;
while ( written < size ) {
retval = write( fd, (const char *)buffer + written, size - written );
if ( retval < 0 ) {
if ( errno != EINTR ) {
break;
}
retval = 0;
}
written += retval;
}
return written;
}
static int16_t buffer[BUFFERSIZE * 2];
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
int result = 0;
FILE * file = 0;
openmpt_module * mod = 0;
int mod_err = OPENMPT_ERROR_OK;
const char * mod_err_str = NULL;
size_t count = 0;
size_t written = 0;
if ( argc != 2 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_stdout SOMEMODULE'." );
goto fail;
}
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
if ( wcslen( argv[1] ) == 0 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_stdout SOMEMODULE'." );
goto fail;
}
file = _wfopen( argv[1], L"rb" );
#else
if ( strlen( argv[1] ) == 0 ) {
fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_stdout SOMEMODULE'." );
goto fail;
}
file = fopen( argv[1], "rb" );
#endif
if ( !file ) {
fprintf( stderr, "Error: %s\n", "fopen() failed." );
goto fail;
}
mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
if ( !mod ) {
libopenmpt_example_print_error( "openmpt_module_create2()", mod_err, mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
goto fail;
}
while ( 1 ) {
openmpt_module_error_clear( mod );
count = openmpt_module_read_interleaved_stereo( mod, SAMPLERATE, BUFFERSIZE, buffer );
mod_err = openmpt_module_error_get_last( mod );
mod_err_str = openmpt_module_error_get_last_message( mod );
if ( mod_err != OPENMPT_ERROR_OK ) {
libopenmpt_example_print_error( "openmpt_module_read_interleaved_stereo()", mod_err, mod_err_str );
openmpt_free_string( mod_err_str );
mod_err_str = NULL;
}
if ( count == 0 ) {
break;
}
written = xwrite( STDOUT_FILENO, buffer, count * 2 * sizeof( int16_t ) );
if ( written == 0 ) {
fprintf( stderr, "Error: %s\n", "write() failed." );
goto fail;
}
}
result = 0;
goto cleanup;
fail:
result = 1;
cleanup:
if ( mod ) {
openmpt_module_destroy( mod );
mod = 0;
}
if ( file ) {
fclose( file );
file = 0;
}
return result;
}