libopenmpt: C API

libopenmpt 0.8.8-pre.0+r25476 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.
*/
#if defined( __MINGW32__ ) && !defined( __MINGW64__ )
#include <sys/types.h>
#endif
#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>
#if defined( __clang__ )
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#elif defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#include <portaudio.h>
#if defined( __clang__ )
#pragma clang diagnostic pop
#elif defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER )
#pragma GCC diagnostic pop
#endif
#if defined( __DJGPP__ )
#include <crt0.h>
#endif /* __DJGPP__ */
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static float left[BUFFERSIZE];
static float right[BUFFERSIZE];
static float * const buffers[2] = { left, right };
#if defined( __DJGPP__ )
/* clang-format off */
int _crt0_startup_flags = 0
| _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */
| _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */
| _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */
| 0;
/* clang-format on */
#endif /* __DJGPP__ */
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
#if defined( __clang__ ) && !defined( _MSC_VER )
int wmain( int argc, wchar_t * argv[] );
#endif
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
#if defined( __DJGPP__ )
/* clang-format off */
_crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */
/* clang-format on */
#endif /* __DJGPP__ */
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_callbacks2(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
#if defined( __clang__ ) && defined( __clang_analyzer__ )
[[clang::suppress]]
#endif
fclose( file );
Pa_Initialize();
Pa_OpenDefaultStream( &stream, 0, 2, paFloat32 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
Pa_StartStream( stream );
while ( 1 ) {
count = openmpt_module_read_float_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;
}
openmpt_stream_get_file_callbacks2
static openmpt_stream_callbacks openmpt_stream_get_file_callbacks2(void)
Provide openmpt_stream_callbacks for standard C FILE objects.
Definition: libopenmpt_stream_callbacks_file.h:132
openmpt_module_destroy
void openmpt_module_destroy(openmpt_module *mod)
Unload a previously created openmpt_module from memory.
openmpt_module_create2
openmpt_module * openmpt_module_create2(openmpt_stream_callbacks stream_callbacks, void *stream, openmpt_log_func logfunc, void *loguser, openmpt_error_func errfunc, void *erruser, int *error, const char **error_message, const openmpt_module_initial_ctl *ctls)
Construct an openmpt_module.
openmpt_module_read_float_stereo
size_t openmpt_module_read_float_stereo(openmpt_module *mod, int32_t samplerate, size_t count, float *left, float *right)
Render audio data.
openmpt_module
struct openmpt_module openmpt_module
Opaque type representing a libopenmpt module.
Definition: libopenmpt.h:660
libopenmpt.h
libopenmpt_stream_callbacks_file.h

## 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
*/
#if defined( unix ) || defined( __unix__ ) || defined( __unix )
#include <unistd.h>
#if defined( _POSIX_VERSION )
#if ( _POSIX_VERSION > 0 )
#ifndef POSIX
#define POSIX
#endif
#if defined( __MINGW32__ ) && !defined( __MINGW64__ )
#include <sys/types.h>
#endif
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libopenmpt/libopenmpt.h>
#if OPENMPT_API_VERSION_AT_LEAST( 0, 7, 0 )
#if defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW ) && defined( __MINGW32__ )
#include <libopenmpt/libopenmpt_stream_callbacks_file_mingw.h>
#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT ) && ( defined( _MSC_VER ) || ( defined( __clang__ ) && defined( _WIN32 ) ) )
#include <libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h>
#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX ) && defined( POSIX ) && defined( _POSIX_C_SOURCE )
#if ( _POSIX_C_SOURCE > 200112L )
#include <libopenmpt/libopenmpt_stream_callbacks_file_posix.h>
#else
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#endif
#else
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#endif
#else
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
#endif
#if defined( __clang__ )
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#elif defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#include <portaudio.h>
#if defined( __clang__ )
#pragma clang diagnostic pop
#elif defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER )
#pragma GCC diagnostic pop
#endif
#if defined( __DJGPP__ )
#include <crt0.h>
#endif /* __DJGPP__ */
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static float left[BUFFERSIZE];
static float right[BUFFERSIZE];
static float * const buffers[2] = { left, right };
static float interleaved_buffer[BUFFERSIZE * 2];
static int is_interleaved = 0;
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( __DJGPP__ )
/* clang-format off */
int _crt0_startup_flags = 0
| _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */
| _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */
| _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */
| 0;
/* clang-format on */
#endif /* __DJGPP__ */
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
#if defined( __clang__ ) && !defined( _MSC_VER )
int wmain( int argc, wchar_t * argv[] );
#endif
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
#if defined( __DJGPP__ )
/* clang-format off */
_crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */
/* clang-format on */
#endif /* __DJGPP__ */
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;
}
#if OPENMPT_API_VERSION_AT_LEAST( 0, 7, 0 )
#if defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW ) && defined( __MINGW32__ )
mod = openmpt_module_create2( openmpt_stream_get_file_mingw_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT ) && ( defined( _MSC_VER ) || ( defined( __clang__ ) && defined( _WIN32 ) ) )
mod = openmpt_module_create2( openmpt_stream_get_file_msvcrt_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX ) && defined( POSIX ) && defined( _POSIX_C_SOURCE )
#if ( _POSIX_C_SOURCE > 200112L )
mod = openmpt_module_create2( openmpt_stream_get_file_posix_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
#else
mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
#endif
#else
mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
#endif
#else
mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
#endif
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, paFloat32 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
if ( pa_error == paSampleFormatNotSupported ) {
is_interleaved = 1;
pa_error = Pa_OpenDefaultStream( &stream, 0, 2, paFloat32, 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 = is_interleaved ? openmpt_module_read_interleaved_float_stereo( mod, SAMPLERATE, BUFFERSIZE, interleaved_buffer ) : openmpt_module_read_float_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 = is_interleaved ? Pa_WriteStream( stream, interleaved_buffer, (unsigned long)count ) : 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;
(void)pa_initialized;
}
if ( mod ) {
openmpt_module_destroy( mod );
mod = 0;
}
if ( file ) {
fclose( file );
file = 0;
}
return result;
}
openmpt_module_read_interleaved_float_stereo
size_t openmpt_module_read_interleaved_float_stereo(openmpt_module *mod, int32_t samplerate, size_t count, float *interleaved_stereo)
Render audio data.
openmpt_free_string
void openmpt_free_string(const char *str)
Free a string returned by libopenmpt.
OPENMPT_ERROR_FUNC_RESULT_DEFAULT
#define OPENMPT_ERROR_FUNC_RESULT_DEFAULT
Definition: libopenmpt.h:413
OPENMPT_ERROR_OK
#define OPENMPT_ERROR_OK
Definition: libopenmpt.h:344
openmpt_stream_get_file_mingw_callbacks
static openmpt_stream_callbacks openmpt_stream_get_file_mingw_callbacks(void)
Provide openmpt_stream_callbacks for standard C FILE objects.
Definition: libopenmpt_stream_callbacks_file_mingw.h:98
openmpt_module_error_get_last
int openmpt_module_error_get_last(openmpt_module *mod)
Get last error.
openmpt_stream_get_file_posix_callbacks
static openmpt_stream_callbacks openmpt_stream_get_file_posix_callbacks(void)
Provide openmpt_stream_callbacks for standard C FILE objects.
Definition: libopenmpt_stream_callbacks_file_posix.h:98
openmpt_stream_get_file_msvcrt_callbacks
static openmpt_stream_callbacks openmpt_stream_get_file_msvcrt_callbacks(void)
Provide openmpt_stream_callbacks for standard C FILE objects.
Definition: libopenmpt_stream_callbacks_file_msvcrt.h:98
OPENMPT_ERROR_OUT_OF_MEMORY
#define OPENMPT_ERROR_OUT_OF_MEMORY
Definition: libopenmpt.h:356
openmpt_stream_get_file_callbacks
static openmpt_stream_callbacks openmpt_stream_get_file_callbacks(void)
Provide openmpt_stream_callbacks for standard C FILE objects.
Definition: libopenmpt_stream_callbacks_file.h:109
openmpt_module_error_clear
void openmpt_module_error_clear(openmpt_module *mod)
Clear last error.
openmpt_error_string
const char * openmpt_error_string(int error)
Convert error code to text.
openmpt_module_set_error_func
void openmpt_module_set_error_func(openmpt_module *mod, openmpt_error_func errfunc, void *erruser)
Set error function.
openmpt_module_error_get_last_message
const char * openmpt_module_error_get_last_message(openmpt_module *mod)
Get last error message.
libopenmpt_stream_callbacks_file_mingw.h
libopenmpt_stream_callbacks_file_msvcrt.h
libopenmpt_stream_callbacks_file_posix.h

## 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
*/
#if defined( __MINGW32__ ) && !defined( __MINGW64__ )
#include <sys/types.h>
#endif
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libopenmpt/libopenmpt.h>
#if defined( __clang__ )
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#elif defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#include <portaudio.h>
#if defined( __clang__ )
#pragma clang diagnostic pop
#elif defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER )
#pragma GCC diagnostic pop
#endif
#if defined( __DJGPP__ )
#include <crt0.h>
#endif /* __DJGPP__ */
#define BUFFERSIZE 480
#define SAMPLERATE 48000
static float left[BUFFERSIZE];
static float right[BUFFERSIZE];
static float * const buffers[2] = { left, right };
static float interleaved_buffer[BUFFERSIZE * 2];
static int is_interleaved = 0;
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)(size_t)(unsigned long)tell_result != (unsigned long)tell_result ) {
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( __DJGPP__ )
/* clang-format off */
int _crt0_startup_flags = 0
| _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */
| _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */
| _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */
| 0;
/* clang-format on */
#endif /* __DJGPP__ */
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
#if defined( __clang__ ) && !defined( _MSC_VER )
int wmain( int argc, wchar_t * argv[] );
#endif
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
#if defined( __DJGPP__ )
/* clang-format off */
_crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */
/* clang-format on */
#endif /* __DJGPP__ */
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;
is_interleaved = 0;
pa_error = Pa_OpenDefaultStream( &stream, 0, 2, paFloat32 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
if ( pa_error == paSampleFormatNotSupported ) {
is_interleaved = 1;
pa_error = Pa_OpenDefaultStream( &stream, 0, 2, paFloat32, 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 = is_interleaved ? openmpt_module_read_interleaved_float_stereo( mod, SAMPLERATE, BUFFERSIZE, interleaved_buffer ) : openmpt_module_read_float_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 = is_interleaved ? Pa_WriteStream( stream, interleaved_buffer, (unsigned long)count ) : 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;
(void)pa_initialized;
}
if ( mod ) {
openmpt_module_destroy( mod );
mod = 0;
}
if ( blob ) {
free_blob( blob );
blob = 0;
}
return result;
}
openmpt_module_create_from_memory2
openmpt_module * openmpt_module_create_from_memory2(const void *filedata, size_t filesize, openmpt_log_func logfunc, void *loguser, openmpt_error_func errfunc, void *erruser, int *error, const char **error_message, const openmpt_module_initial_ctl *ctls)
Construct an openmpt_module.

## 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
*/
#if defined( __MINGW32__ ) && !defined( __MINGW64__ )
#include <sys/types.h>
#endif
#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>
#if defined( __DJGPP__ )
#include <crt0.h>
#endif /* __DJGPP__ */
#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( __DJGPP__ )
/* clang-format off */
int _crt0_startup_flags = 0
| _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */
| _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */
| _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */
| 0;
/* clang-format on */
#endif /* __DJGPP__ */
#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
#if defined( __clang__ ) && !defined( _MSC_VER )
int wmain( int argc, wchar_t * argv[] );
#endif
int wmain( int argc, wchar_t * argv[] ) {
#else
int main( int argc, char * argv[] ) {
#endif
#if defined( __DJGPP__ )
/* clang-format off */
_crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */
/* clang-format on */
#endif /* __DJGPP__ */
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_callbacks2(), 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;
}
openmpt_module_read_interleaved_stereo
size_t openmpt_module_read_interleaved_stereo(openmpt_module *mod, int32_t samplerate, size_t count, int16_t *interleaved_stereo)
Render audio data.