#pragma once #include #include "opmfile.h" // OPMPlay setup defines #define OPMPLAY_ENABLE_STDIO #ifdef OPMPLAY_ENABLE_STDIO #include #include #include #endif // LXMPlay import defines #define opmplay_memcpy memcpy #define opmplay_memset memset #define opmplay_memcmp memcmp #define opmplay_alloc malloc #define opmplay_memfree free #define opmplay_debug_printf(...) printf(__VA_ARGS__) #ifdef __cplusplus extern "C" { #endif // general enums enum { OPMPLAY_MAX_CHANNLES = 16, OPMPLAY_MAX_STACK_DEPTH = 4, }; // return error codes enum { OPMPLAY_ERR_OK = 0, OPMPLAY_ERR_END_OF_STREAM = 1, OPMPLAY_ERR_BAD_FILE_STRUCTURE = -1, OPMPLAY_ERR_MEMALLOC = -2, OPMPLAY_ERR_NULLPTR = -3, OPMPLAY_ERR_NO_SOUNDRAM = -4, OPMPLAY_ERR_DEVICE = -5, OPMPLAY_ERR_BAD_PARAMETER = -6, OPMPLAY_ERR_IO = -7, OPMPLAY_ERR_UNKNOWN = -20, }; enum { OPMPLAY_IO_USER = 0, OPMPLAY_IO_FILE = 1, OPMPLAY_IO_MEMORY = 2, }; // file I/O structs struct opmplay_io_t { uint32_t type; // i/o type union { void* buf; #ifdef OPMPLAY_ENABLE_STDIO FILE* io; #endif }; uint32_t size; // internal uint32_t offset; uint32_t(*read)(opmplay_io_t* io, void* dst, uint32_t size); // returns bytes read uint32_t(*seek)(opmplay_io_t* io, uint32_t offset); // returns 0 if success }; struct opmplay_channel_stack_t { const uint8_t* ptr; uint16_t frames_to_play; }; struct opmplay_channel_context_t { // stack opmplay_channel_stack_t stack[OPMPLAY_MAX_STACK_DEPTH]; uint16_t stack_pos; // stream data struct { uint16_t samples_to_play; uint16_t delay; uint16_t reload; const uint8_t* data; const uint8_t* ptr; const uint8_t* loop; // if active } stream; // private stuff uint8_t block; // cached block register }; struct opmplay_context_t { // LXM file header opm_header_t header; // channel context opmplay_channel_context_t channels[OPMPLAY_MAX_CHANNLES]; // position data struct { uint16_t frame; uint16_t frame_looped; uint32_t samples; } pos; // private stuff uint8_t ssg_r7[2]; // cached SSG mask register uint8_t extch3_block[2][3]; // cached extch3 block }; // init context int opmplay_init(opmplay_context_t* ctx); // free context int opmplay_free(opmplay_context_t* ctx); // load file header int opmplay_load_header(opmplay_context_t* ctx, opmplay_io_t* io); // load file contents int opmplay_load_module(opmplay_context_t* ctx, opmplay_io_t* io); // reset to start int opmplay_rewind(opmplay_context_t* ctx); // play one tick, render changes to opl3 device int opmplay_tick(opmplay_context_t* ctx); #ifdef __cplusplus } #endif