From 6ed9f7604acc06003658e90e47c312acc5f6a9f0 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 19 Sep 2014 16:58:07 +0200 Subject: [PATCH 01/18] fixed FindGDIPLUS.cmake to match MSYS2/Mingw-w64 libgdiplus path --- cmake/FindGDIPLUS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindGDIPLUS.cmake b/cmake/FindGDIPLUS.cmake index 66ed629e47..ba9257d63a 100644 --- a/cmake/FindGDIPLUS.cmake +++ b/cmake/FindGDIPLUS.cmake @@ -17,7 +17,7 @@ else() set(GDIPLUS_LOWERCASE 1 CACHE INTERNAL "Is GdiPlus.h spelt with lowercase?") endif() -find_library(GDIPLUS_LIBRARY NAMES gdiplus) +find_library(GDIPLUS_LIBRARY NAMES libgdiplus gdiplus) # Handle the QUIETLY and REQUIRED arguments and set GDIPLUS_FOUND to TRUE if # all listed variables are TRUE. From e03eb8bfdc263e4700e56f839ee34245a8fe761a Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 2 Jan 2015 17:11:41 +0100 Subject: [PATCH 02/18] Added support for Creative Voice audio file format through libsndfile. Also added a proper Cmake FindSndfile.cmake script. --- addons/acodec/CMakeLists.txt | 57 ++++ addons/acodec/acodec.c | 7 + addons/acodec/acodec.h | 5 + .../internal/aintern_acodec_cfg.h.cmake | 3 + addons/acodec/voc.c | 299 ++++++++++++++++++ cmake/FindSndfile.cmake | 28 ++ 6 files changed, 399 insertions(+) create mode 100644 addons/acodec/voc.c create mode 100644 cmake/FindSndfile.cmake diff --git a/addons/acodec/CMakeLists.txt b/addons/acodec/CMakeLists.txt index 73afe69334..519c438791 100644 --- a/addons/acodec/CMakeLists.txt +++ b/addons/acodec/CMakeLists.txt @@ -4,6 +4,7 @@ option(WANT_FLAC "Enable FLAC support" on) option(WANT_VORBIS "Enable Ogg Vorbis support using libvorbis" on) option(WANT_TREMOR "Enable Ogg Vorbis support using Tremor" off) option(WANT_MODAUDIO "Enable MOD Audio support" on) +option(WANT_CREATIVE_VOICE_AUDIO "Enable VOC (Creative Voice) Audio support" on) option(WANT_ACODEC_DYNAMIC_LOAD "Enable DLL loading in acodec (Windows)" on) #-----------------------------------------------------------------------------# @@ -260,6 +261,62 @@ if(SUPPORT_VORBIS) endif() endif(SUPPORT_VORBIS) +# +# VOC (Creative Voice) audio +# + +if(WANT_CREATIVE_VOICE_AUDIO) + find_package(SNDFILE) + if(SNDFILE_FOUND) + set(CMAKE_REQUIRED_INCLUDES ${SNDFILE_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${SNDFILE_LIBRARIES}) + check_c_source_compiles(" + #include + int main(void) + { + char buffer[128]; + sf_command(NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)); + return 0; + }" + SNDFILE_COMPILES) + set(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_REQUIRED_LIBRARIES) + if(SNDFILE_COMPILES) + set(SUPPORT_CREATIVE_VOICE_AUDIO 1) + else() + message("libsndfile compile test FAILED") + endif(SNDFILE_COMPILES) + endif(SNDFILE_FOUND) + if(NOT SUPPORT_CREATIVE_VOICE_AUDIO) + message("WARNING: SNDFILE not found or compile test failed," + "disabling support. ") + endif(NOT SUPPORT_CREATIVE_VOICE_AUDIO) +endif(WANT_CREATIVE_VOICE_AUDIO) + +if(SUPPORT_CREATIVE_VOICE_AUDIO) + include_directories(SYSTEM ${SNDFILE_INCLUDE_DIR}) + set(ALLEGRO_CFG_ACODEC_CREATIVE_VOICE 1) + list(APPEND ACODEC_SOURCES voc.c) + + list(APPEND ACODEC_INCLUDE_DIRECTORIES ${SNDFILE_INCLUDE_DIR}) + + if(WIN32 AND WANT_ACODEC_DYNAMIC_LOAD) + if(SNDFILE_LIBRARY MATCHES "${WIN32_STATIC_LIB_REGEX}") + message("WARNING: Dynamic loading will be disabled for SNDFILE" + " as static library was found: ${SNDFILE_LIBRARY};" + "NOTE: licensing of SNDFILE (under LGLPL v2/v3) requires " + "this code to be licended under GPL. " + "for more information: http://www.mega-nerd.com/SNDFILE/#Licensing") + else() + get_dll_name(${SNDFILE_LIBRARY} ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL) + endif() + endif() + + if(NOT ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL) + list(APPEND ACODEC_LIBRARIES ${SNDFILE_LIBRARIES}) + endif() +endif() + configure_file( allegro5/internal/aintern_acodec_cfg.h.cmake ${CMAKE_BINARY_DIR}/include/allegro5/internal/aintern_acodec_cfg.h diff --git a/addons/acodec/acodec.c b/addons/acodec/acodec.c index f902b61b3b..66d508cebc 100644 --- a/addons/acodec/acodec.c +++ b/addons/acodec/acodec.c @@ -51,6 +51,13 @@ bool al_init_acodec_addon(void) ret &= al_register_audio_stream_loader_f(".ogg", _al_load_ogg_vorbis_audio_stream_f); #endif +#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE + ret &= al_register_sample_loader(".VOC", _al_load_creative_voice); +// ret &= al_register_audio_stream_loader(".VOC", _al_load_VOC_audio_stream); +// ret &= al_register_sample_loader_f(".VOC", _al_load_VOC_f); +// ret &= al_register_audio_stream_loader_f(".VOC", _al_load_VOC_audio_stream_f); +#endif + return ret; } diff --git a/addons/acodec/acodec.h b/addons/acodec/acodec.h index 9f2dbb6c3f..7bf436479c 100644 --- a/addons/acodec/acodec.h +++ b/addons/acodec/acodec.h @@ -49,4 +49,9 @@ ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples); #endif +#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE +ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename); +ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file); +#endif + #endif diff --git a/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake b/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake index 84d4972a99..e56e8f6b85 100644 --- a/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake +++ b/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake @@ -2,8 +2,11 @@ #cmakedefine ALLEGRO_CFG_ACODEC_MODAUDIO #cmakedefine ALLEGRO_CFG_ACODEC_VORBIS #cmakedefine ALLEGRO_CFG_ACODEC_TREMOR +#cmakedefine ALLEGRO_CFG_ACODEC_CREATIVE_VOICE + /* Define if the library should be loaded dynamically. */ #cmakedefine ALLEGRO_CFG_ACODEC_FLAC_DLL "@ALLEGRO_CFG_ACODEC_FLAC_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_DUMB_DLL "@ALLEGRO_CFG_ACODEC_DUMB_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_VORBISFILE_DLL "@ALLEGRO_CFG_ACODEC_VORBISFILE_DLL@" +#cmakedefine ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL "@ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL@" diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c new file mode 100644 index 0000000000..f29acbac16 --- /dev/null +++ b/addons/acodec/voc.c @@ -0,0 +1,299 @@ +/* + * Allegro5 Creative Voice Reader. + * Based on external libsndfile usage + * Can only load samples right now + * author: pkrcel (aka Andrea Provasi) + */ + +#include "allegro5/allegro.h" +#include "allegro5/allegro_acodec.h" +#include "allegro5/allegro_audio.h" +#include "allegro5/internal/aintern.h" +#include "allegro5/internal/aintern_audio.h" +#include "allegro5/internal/aintern_exitfunc.h" +#include "allegro5/internal/aintern_system.h" +#include "acodec.h" +#include "helper.h" + +#ifndef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE + #error configuration problem, ALLEGRO_CFG_ACODEC_CREATIVE_VOICE not set +#endif + +ALLEGRO_DEBUG_CHANNEL("acodec") + +#include + +typedef struct AL_SNDFILE_DATA AL_SNDFILE_DATA; + +struct AL_SNDFILE_DATA { + SNDFILE *sf; + SF_INFO sfinfo; + ALLEGRO_FILE *file; + SF_VIRTUAL_IO al_sd_vio; +}; + + +/* dynamic loading support (Windows only currently) */ +#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL +static void *cva_dll = NULL; +static bool cva_virgin = true; +#endif + +static struct +{ + SNDFILE* (*sf_open_virtual) (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data); +// int (*sf_error) (SNDFILE *); +// const char* (*sf_strerror) (SNDFILE *); +// const char* (*sf_error_number) (int) ; +// int (*sf_command) (SNDFILE *, int , void *, int ) ; + + sf_count_t (*sf_readf_short) (SNDFILE *, short *, sf_count_t ) ; +// sf_count_t (*sf_writef_short) (SNDFILE *, const short *, sf_count_t ) ; +// sf_count_t (*sf_readf_int) (SNDFILE *, int *, sf_count_t ) ; +// sf_count_t (*sf_writef_int) (SNDFILE *, const int *, sf_count_t ) ; +// sf_count_t (*sf_readf_float) (SNDFILE *, float *, sf_count_t ) ; +// sf_count_t (*sf_writef_float) (SNDFILE *, const float *, sf_count_t ) ; +// sf_count_t (*sf_readf_double) (SNDFILE *, double *, sf_count_t ) ; +// sf_count_t (*sf_writef_double) (SNDFILE *, const double *, sf_count_t ) ; + + sf_count_t (*sf_read_short) (SNDFILE *, short *, sf_count_t ) ; +// sf_count_t (*sf_write_short) (SNDFILE *, const short *, sf_count_t ) ; +// sf_count_t (*sf_read_int) (SNDFILE *, int *, sf_count_t ) ; +// sf_count_t (*sf_write_int) (SNDFILE *, const int *, sf_count_t ) ; +// sf_count_t (*sf_read_float) (SNDFILE *, float *, sf_count_t ) ; +// sf_count_t (*sf_write_float) (SNDFILE *, const float *, sf_count_t ) ; +// sf_count_t (*sf_read_double) (SNDFILE *, double *, sf_count_t ) ; +// sf_count_t (*sf_write_double) (SNDFILE *, const double *, sf_count_t ) ; + + int (*sf_close) (SNDFILE *) ; +} lib; + + +#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL +static void shutdown_dynlib(void) +{ + if (cva_dll) { + _al_close_library(cva_dll); + cva_dll = NULL; + cva_virgin = true; + } +} +#endif + + +static bool init_dynlib(void) +{ +#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL + if (cva_dll) { + return true; + } + + if (!cva_virgin) { + return false; + } + + cva_virgin = false; + + cva_dll = _al_open_library(ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL); + if (!cva_dll) { + ALLEGRO_WARN("Could not load " ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL "\n"); + return false; + } + + _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); + + #define INITSYM(x) \ + do \ + { \ + lib.x = _al_import_symbol(cva_dll, #x); \ + if (lib.x == 0) { \ + ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ + return false; \ + } \ + } while(0) +#else + #define INITSYM(x) (lib.x = (x)) +#endif + + memset(&lib, 0, sizeof(lib)); + + INITSYM(sf_open_virtual); + INITSYM(sf_readf_short); + INITSYM(sf_read_short); + INITSYM(sf_close); + + return true; + +#undef INITSYM +} + +/* + * Providing SF_VIRTUAL_IO functions to later be called on sf_open_virtual + */ + +static sf_count_t _al_sf_vio_get_filelen(void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; + return (sf_count_t)al_fsize(f); +} + +static sf_count_t _al_sf_vio_seek (sf_count_t offset, int whence, void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; + + switch(whence) { + case SEEK_SET: whence = ALLEGRO_SEEK_SET; break; + case SEEK_CUR: whence = ALLEGRO_SEEK_CUR; break; + case SEEK_END: whence = ALLEGRO_SEEK_END; break; + } + if (!al_fseek(f, offset, whence)) { + return -1; + } else { + return (sf_count_t)al_ftell(f); + } +} + +static sf_count_t _al_sf_vio_read(void *ptr, sf_count_t count, void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; + size_t nrbytes = 0; + + nrbytes = al_fread(f, ptr, count); + + return nrbytes; +} + +static sf_count_t _al_sf_vio_write(const void *ptr, sf_count_t count, void *user_data){ + // won't implement, we do not need to write to a virtual IO so far + return 0; +} + +static sf_count_t _al_sf_vio_tell(void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; + sf_count_t ret = 0; + + ret = al_ftell(f); + if (ret == -1) + return -1; + + return ret; +} + + +ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename) +{ + ALLEGRO_FILE *f; + ALLEGRO_SAMPLE *spl; + ASSERT(filename); + + ALLEGRO_INFO("Loading sample %s.\n", filename); + f = al_fopen(filename, "rb"); + if (!f) { + ALLEGRO_WARN("Failed reading %s.\n", filename); + return NULL; + } + + spl = _al_load_creative_voice_f(f); + + al_fclose(f); + + return spl; +} + + +ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) +{ + /* Note: decoding library returns "whatever we want" as far it is transparent + * To conform to other acodec handlers, we'll use 16-bit "short" an no other + * Might change in the future. + */ + + //endinanees check might be superfluos +#ifdef ALLEGRO_LITTLE_ENDIAN + //const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ +#else + //const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ +#endif + + //const int packet_size = 4096; /* suggestion for size to read at a time */ + const int word_size = 2; /* constant for 16-bit */ + + short *buffer; + long pos; + ALLEGRO_SAMPLE *sample; + int channels; + long samplerate; + long total_samples; + long total_size; + AL_SNDFILE_DATA al_sd; + long read; + + if (!init_dynlib()) { + return NULL; + } + + //Initialize the sndfile object + memset(&al_sd, 0, sizeof(al_sd)); + al_sd.al_sd_vio.get_filelen = _al_sf_vio_get_filelen; + al_sd.al_sd_vio.read = _al_sf_vio_read; + al_sd.al_sd_vio.write = _al_sf_vio_write; + al_sd.al_sd_vio.seek = _al_sf_vio_seek; + al_sd.al_sd_vio.tell = _al_sf_vio_tell; + al_sd.file = file; + + + // We need to open the file to get the parameters + al_sd.sf = lib.sf_open_virtual(&al_sd.al_sd_vio, SFM_READ, &al_sd.sfinfo, al_sd.file); + + + channels = al_sd.sfinfo.channels; + samplerate = al_sd.sfinfo.samplerate; + total_samples = al_sd.sfinfo.frames; + + total_size = total_samples * channels * word_size; + + ALLEGRO_DEBUG("channels %d\n", channels); + ALLEGRO_DEBUG("word_size %d\n", word_size); + ALLEGRO_DEBUG("rate %ld\n", samplerate); + ALLEGRO_DEBUG("total_samples %ld\n", total_samples); + ALLEGRO_DEBUG("total_size %ld\n", total_size); + + buffer = al_malloc(total_size); + if (!buffer) { + return NULL; + } + + /* + * libsndfile allows us to not read in chunks but this is STILL safer than + * an all-or-nothing whole file read, I guess + */ + +// pos = 0; +// while (pos < total_size) { +// const int read_size = _ALLEGRO_MIN(packet_size, total_size - pos); +// ASSERT(pos + read_size <= total_size); + +// /* TODO: lacks error handling, implement sooner than later*/ +// read = lib.sf_read_short(al_sd.sf, buffer + pos, read_size); + +// pos += read; +// if (read == 0) +// break; +// } + + read = lib.sf_readf_short(al_sd.sf, buffer, al_sd.sfinfo.frames); + sample = al_create_sample(buffer, total_samples, samplerate, + _al_word_size_to_depth_conf(word_size), + _al_count_to_channel_conf(channels), true); + + if (!sample) { + al_free(buffer); + } + + lib.sf_close(al_sd.sf); + + return sample; +} + +/* + * + * Should Implement also stream seek. + * + */ diff --git a/cmake/FindSndfile.cmake b/cmake/FindSndfile.cmake new file mode 100644 index 0000000000..ac8a63569d --- /dev/null +++ b/cmake/FindSndfile.cmake @@ -0,0 +1,28 @@ +# - Find sndfile +# Find the native sndfile includes and libraries +# +# SNDFILE_INCLUDE_DIR - where to find sndfile.h, etc. +# SNDFILE_LIBRARIES - List of libraries when using libsndfile. +# SNDFILE_FOUND - True if libsndfile found. + +if(SNDFILE_INCLUDE_DIR) + # Already in cache, be silent + set(SNDFILE_FIND_QUIETLY TRUE) +endif(SNDFILE_INCLUDE_DIR) + +find_path(SNDFILE_INCLUDE_DIR sndfile.h) + +find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1) + +# Handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if +# all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SNDFILE DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR) + +if(SNDFILE_FOUND) + set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY}) +else(SNDFILE_FOUND) + set(SNDFILE_LIBRARIES) +endif(SNDFILE_FOUND) + +mark_as_advanced(SNDFILE_INCLUDE_DIR SNDFILE_LIBRARY) From c7abfd7806799a460e1e0f1c3db521c6890f57da Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 2 Jan 2015 21:15:31 +0100 Subject: [PATCH 03/18] Beauify source of voc.c and add some comments for maintenance. --- addons/acodec/voc.c | 126 ++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index f29acbac16..bdc91b6353 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -1,8 +1,14 @@ /* - * Allegro5 Creative Voice Reader. - * Based on external libsndfile usage - * Can only load samples right now + * Allegro5 Creative Voice Audio Reader. + * + * Requires libsndfile + * * author: pkrcel (aka Andrea Provasi) + * + * Revisions: + * 2014-12-30 Initial Release - can only load samples + * 2015-01-02 Source check and complete test with ex_acodec + * First pull requesto to Allegro Dev team */ #include "allegro5/allegro.h" @@ -41,31 +47,32 @@ static bool cva_virgin = true; static struct { - SNDFILE* (*sf_open_virtual) (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data); + SNDFILE* (*sf_open_virtual) (SF_VIRTUAL_IO *sfvirtual, int mode, + SF_INFO *sfinfo, void *user_data); // int (*sf_error) (SNDFILE *); // const char* (*sf_strerror) (SNDFILE *); -// const char* (*sf_error_number) (int) ; -// int (*sf_command) (SNDFILE *, int , void *, int ) ; - - sf_count_t (*sf_readf_short) (SNDFILE *, short *, sf_count_t ) ; -// sf_count_t (*sf_writef_short) (SNDFILE *, const short *, sf_count_t ) ; -// sf_count_t (*sf_readf_int) (SNDFILE *, int *, sf_count_t ) ; -// sf_count_t (*sf_writef_int) (SNDFILE *, const int *, sf_count_t ) ; -// sf_count_t (*sf_readf_float) (SNDFILE *, float *, sf_count_t ) ; -// sf_count_t (*sf_writef_float) (SNDFILE *, const float *, sf_count_t ) ; -// sf_count_t (*sf_readf_double) (SNDFILE *, double *, sf_count_t ) ; -// sf_count_t (*sf_writef_double) (SNDFILE *, const double *, sf_count_t ) ; - - sf_count_t (*sf_read_short) (SNDFILE *, short *, sf_count_t ) ; -// sf_count_t (*sf_write_short) (SNDFILE *, const short *, sf_count_t ) ; -// sf_count_t (*sf_read_int) (SNDFILE *, int *, sf_count_t ) ; -// sf_count_t (*sf_write_int) (SNDFILE *, const int *, sf_count_t ) ; -// sf_count_t (*sf_read_float) (SNDFILE *, float *, sf_count_t ) ; +// const char* (*sf_error_number) (int); +// int (*sf_command) (SNDFILE *, int , void *, int ); + + sf_count_t (*sf_readf_short) (SNDFILE *, short *, sf_count_t ); +// sf_count_t (*sf_writef_short) (SNDFILE *, const short *, sf_count_t ); +// sf_count_t (*sf_readf_int) (SNDFILE *, int *, sf_count_t ); +// sf_count_t (*sf_writef_int) (SNDFILE *, const int *, sf_count_t ); +// sf_count_t (*sf_readf_float) (SNDFILE *, float *, sf_count_t ); +// sf_count_t (*sf_writef_float) (SNDFILE *, const float *, sf_count_t ); +// sf_count_t (*sf_readf_double) (SNDFILE *, double *, sf_count_t ); +// sf_count_t (*sf_writef_double) (SNDFILE *, const double *, sf_count_t ); + + sf_count_t (*sf_read_short) (SNDFILE *, short *, sf_count_t ); +// sf_count_t (*sf_write_short) (SNDFILE *, const short *, sf_count_t ); +// sf_count_t (*sf_read_int) (SNDFILE *, int *, sf_count_t ); +// sf_count_t (*sf_write_int) (SNDFILE *, const int *, sf_count_t ); +// sf_count_t (*sf_read_float) (SNDFILE *, float *, sf_count_t ); // sf_count_t (*sf_write_float) (SNDFILE *, const float *, sf_count_t ) ; -// sf_count_t (*sf_read_double) (SNDFILE *, double *, sf_count_t ) ; -// sf_count_t (*sf_write_double) (SNDFILE *, const double *, sf_count_t ) ; +// sf_count_t (*sf_read_double) (SNDFILE *, double *, sf_count_t ); +// sf_count_t (*sf_write_double) (SNDFILE *, const double *, sf_count_t ); - int (*sf_close) (SNDFILE *) ; + int (*sf_close) (SNDFILE *); } lib; @@ -128,9 +135,11 @@ static bool init_dynlib(void) } /* - * Providing SF_VIRTUAL_IO functions to later be called on sf_open_virtual + * Providing SF_VIRTUAL_IO environment + * these functions have to be passed later to sf_open_virtual + * For mor information: + * */ - static sf_count_t _al_sf_vio_get_filelen(void *user_data){ ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; return (sf_count_t)al_fsize(f); @@ -160,8 +169,11 @@ static sf_count_t _al_sf_vio_read(void *ptr, sf_count_t count, void *user_data){ return nrbytes; } +/* + * This is not yet implemented, current release does not save samples. + * + */ static sf_count_t _al_sf_vio_write(const void *ptr, sf_count_t count, void *user_data){ - // won't implement, we do not need to write to a virtual IO so far return 0; } @@ -200,28 +212,23 @@ ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename) ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) { - /* Note: decoding library returns "whatever we want" as far it is transparent + /* NOTE: The decoding library libsndfile returns "whatever we want" + * and is transparent to the user. * To conform to other acodec handlers, we'll use 16-bit "short" an no other - * Might change in the future. + * format as the 16Bit PCM data seems to be the most commonly supported. + * + * The decoding library uses the native endian format of the host, so no need + * to check curent endianess. */ - //endinanees check might be superfluos -#ifdef ALLEGRO_LITTLE_ENDIAN - //const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ -#else - //const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ -#endif + const int word_size = 2; /* constant stands for 16-bit */ - //const int packet_size = 4096; /* suggestion for size to read at a time */ - const int word_size = 2; /* constant for 16-bit */ - - short *buffer; - long pos; + short *buffer; /* the actual PCM data buffer */ ALLEGRO_SAMPLE *sample; int channels; long samplerate; long total_samples; - long total_size; + long total_size; /* unsure about how I handle this */ AL_SNDFILE_DATA al_sd; long read; @@ -229,7 +236,7 @@ ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) return NULL; } - //Initialize the sndfile object + /* Initialize the sndfile object we pass to the decoder*/ memset(&al_sd, 0, sizeof(al_sd)); al_sd.al_sd_vio.get_filelen = _al_sf_vio_get_filelen; al_sd.al_sd_vio.read = _al_sf_vio_read; @@ -239,9 +246,15 @@ ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) al_sd.file = file; - // We need to open the file to get the parameters - al_sd.sf = lib.sf_open_virtual(&al_sd.al_sd_vio, SFM_READ, &al_sd.sfinfo, al_sd.file); + /* Need to open the file first to get the parameters + * + * TODO: inser proper error handling, even thou the ALLEGRO_FILE should + * already have been properly handled by the caller + * + */ + al_sd.sf = lib.sf_open_virtual(&al_sd.al_sd_vio, SFM_READ, + &al_sd.sfinfo, al_sd.file); channels = al_sd.sfinfo.channels; samplerate = al_sd.sfinfo.samplerate; @@ -261,24 +274,13 @@ ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) } /* - * libsndfile allows us to not read in chunks but this is STILL safer than - * an all-or-nothing whole file read, I guess + * libsndfile allows us to read all the buffer in "frames". + * Given that 'total_size' is correct, there should not be any overrun. + * NOTE: 'read' is unused by it might be beneficial to add a sanity check + * having it compared to the total frames actually read and the expected. */ - -// pos = 0; -// while (pos < total_size) { -// const int read_size = _ALLEGRO_MIN(packet_size, total_size - pos); -// ASSERT(pos + read_size <= total_size); - -// /* TODO: lacks error handling, implement sooner than later*/ -// read = lib.sf_read_short(al_sd.sf, buffer + pos, read_size); - -// pos += read; -// if (read == 0) -// break; -// } - read = lib.sf_readf_short(al_sd.sf, buffer, al_sd.sfinfo.frames); + sample = al_create_sample(buffer, total_samples, samplerate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels), true); @@ -293,7 +295,7 @@ ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) } /* - * - * Should Implement also stream seek. + * TODO: + * Should also provide a STREAM implementation. * */ From 8266ff88c11ad5ac295b69f7e72ff00fdfab758e Mon Sep 17 00:00:00 2001 From: pkrcel Date: Mon, 5 Jan 2015 00:32:46 +0100 Subject: [PATCH 04/18] Changed libsndfile link implementation to sndfile.c and added an internal VOC decoder --- addons/acodec/CMakeLists.txt | 26 +- addons/acodec/acodec.c | 10 +- addons/acodec/acodec.h | 15 +- .../internal/aintern_acodec_cfg.h.cmake | 4 +- addons/acodec/sndfile.c | 307 +++++++++++ addons/acodec/voc.c | 477 +++++++++--------- 6 files changed, 593 insertions(+), 246 deletions(-) create mode 100644 addons/acodec/sndfile.c diff --git a/addons/acodec/CMakeLists.txt b/addons/acodec/CMakeLists.txt index 519c438791..57ebdc75b2 100644 --- a/addons/acodec/CMakeLists.txt +++ b/addons/acodec/CMakeLists.txt @@ -4,7 +4,7 @@ option(WANT_FLAC "Enable FLAC support" on) option(WANT_VORBIS "Enable Ogg Vorbis support using libvorbis" on) option(WANT_TREMOR "Enable Ogg Vorbis support using Tremor" off) option(WANT_MODAUDIO "Enable MOD Audio support" on) -option(WANT_CREATIVE_VOICE_AUDIO "Enable VOC (Creative Voice) Audio support" on) +option(WANT_SNDFILE_AUDIO "Enable libsndfile as External Audio " off) option(WANT_ACODEC_DYNAMIC_LOAD "Enable DLL loading in acodec (Windows)" on) #-----------------------------------------------------------------------------# @@ -19,6 +19,7 @@ set(ACODEC_SOURCES acodec.c wav.c helper.c + voc.c # built-in enhanced port of A4 loader ) set(ACODEC_LIBRARIES) @@ -262,10 +263,11 @@ if(SUPPORT_VORBIS) endif(SUPPORT_VORBIS) # -# VOC (Creative Voice) audio +# SNDFILE (libsndfile) audio +# adds support for libsndfile offline decoder. # -if(WANT_CREATIVE_VOICE_AUDIO) +if(WANT_SNDFILE_AUDIO) find_package(SNDFILE) if(SNDFILE_FOUND) set(CMAKE_REQUIRED_INCLUDES ${SNDFILE_INCLUDE_DIR}) @@ -282,21 +284,21 @@ if(WANT_CREATIVE_VOICE_AUDIO) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) if(SNDFILE_COMPILES) - set(SUPPORT_CREATIVE_VOICE_AUDIO 1) + set(SUPPORT_SNDFILE_AUDIO 1) else() message("libsndfile compile test FAILED") endif(SNDFILE_COMPILES) endif(SNDFILE_FOUND) - if(NOT SUPPORT_CREATIVE_VOICE_AUDIO) + if(NOT SUPPORT_SNDFILE_AUDIO) message("WARNING: SNDFILE not found or compile test failed," "disabling support. ") - endif(NOT SUPPORT_CREATIVE_VOICE_AUDIO) -endif(WANT_CREATIVE_VOICE_AUDIO) + endif(NOT SUPPORT_SNDFILE_AUDIO) +endif(WANT_SNDFILE_AUDIO) -if(SUPPORT_CREATIVE_VOICE_AUDIO) +if(SUPPORT_SNDFILE_AUDIO) include_directories(SYSTEM ${SNDFILE_INCLUDE_DIR}) - set(ALLEGRO_CFG_ACODEC_CREATIVE_VOICE 1) - list(APPEND ACODEC_SOURCES voc.c) + set(ALLEGRO_CFG_ACODEC_SNDFILE 1) + list(APPEND ACODEC_SOURCES sndfile.c) list(APPEND ACODEC_INCLUDE_DIRECTORIES ${SNDFILE_INCLUDE_DIR}) @@ -308,11 +310,11 @@ if(SUPPORT_CREATIVE_VOICE_AUDIO) "this code to be licended under GPL. " "for more information: http://www.mega-nerd.com/SNDFILE/#Licensing") else() - get_dll_name(${SNDFILE_LIBRARY} ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL) + get_dll_name(${SNDFILE_LIBRARY} ALLEGRO_CFG_ACODEC_SNDFILE_DLL) endif() endif() - if(NOT ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL) + if(NOT ALLEGRO_CFG_ACODEC_SNDFILE_DLL) list(APPEND ACODEC_LIBRARIES ${SNDFILE_LIBRARIES}) endif() endif() diff --git a/addons/acodec/acodec.c b/addons/acodec/acodec.c index 66d508cebc..c0050362ae 100644 --- a/addons/acodec/acodec.c +++ b/addons/acodec/acodec.c @@ -51,10 +51,14 @@ bool al_init_acodec_addon(void) ret &= al_register_audio_stream_loader_f(".ogg", _al_load_ogg_vorbis_audio_stream_f); #endif -#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE - ret &= al_register_sample_loader(".VOC", _al_load_creative_voice); +#ifdef ALLEGRO_CFG_ACODEC_SNDFILE + /* + * These are here for placeholder on a format actually read by sndfile + */ + ret &= al_register_sample_loader(".aiff", _al_load_sndfile); // ret &= al_register_audio_stream_loader(".VOC", _al_load_VOC_audio_stream); -// ret &= al_register_sample_loader_f(".VOC", _al_load_VOC_f); + + ret &= al_register_sample_loader_f(".aiff", _al_load_sndfile_f); // ret &= al_register_audio_stream_loader_f(".VOC", _al_load_VOC_audio_stream_f); #endif diff --git a/addons/acodec/acodec.h b/addons/acodec/acodec.h index 7bf436479c..3ad26852d1 100644 --- a/addons/acodec/acodec.h +++ b/addons/acodec/acodec.h @@ -12,6 +12,15 @@ ALLEGRO_AUDIO_STREAM *_al_load_wav_audio_stream_f(ALLEGRO_FILE* f, bool _al_save_wav(const char *filename, ALLEGRO_SAMPLE *spl); bool _al_save_wav_f(ALLEGRO_FILE *pf, ALLEGRO_SAMPLE *spl); +/* + * Built-in Port of A4 Creative Voice file (.voc) Loader. + * should not implement streams since it's unlikely this container + * will ever be used as such. + */ +ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename); +ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *fp); + + #ifdef ALLEGRO_CFG_ACODEC_FLAC ALLEGRO_SAMPLE *_al_load_flac(const char *filename); ALLEGRO_SAMPLE *_al_load_flac_f(ALLEGRO_FILE *f); @@ -49,9 +58,9 @@ ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples); #endif -#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE -ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename); -ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file); +#ifdef ALLEGRO_CFG_ACODEC_SNDFILE +ALLEGRO_SAMPLE *_al_load_sndfile(const char *filename); +ALLEGRO_SAMPLE *_al_load_sndfile_f(ALLEGRO_FILE *file); #endif #endif diff --git a/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake b/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake index e56e8f6b85..29c86555eb 100644 --- a/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake +++ b/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake @@ -2,11 +2,11 @@ #cmakedefine ALLEGRO_CFG_ACODEC_MODAUDIO #cmakedefine ALLEGRO_CFG_ACODEC_VORBIS #cmakedefine ALLEGRO_CFG_ACODEC_TREMOR -#cmakedefine ALLEGRO_CFG_ACODEC_CREATIVE_VOICE +#cmakedefine ALLEGRO_CFG_ACODEC_SNDFILE /* Define if the library should be loaded dynamically. */ #cmakedefine ALLEGRO_CFG_ACODEC_FLAC_DLL "@ALLEGRO_CFG_ACODEC_FLAC_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_DUMB_DLL "@ALLEGRO_CFG_ACODEC_DUMB_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_VORBISFILE_DLL "@ALLEGRO_CFG_ACODEC_VORBISFILE_DLL@" -#cmakedefine ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL "@ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL@" +#cmakedefine ALLEGRO_CFG_ACODEC_SNDFILE_DLL "@ALLEGRO_CFG_ACODEC_SNDFILE_DLL@" diff --git a/addons/acodec/sndfile.c b/addons/acodec/sndfile.c new file mode 100644 index 0000000000..cb140e1d23 --- /dev/null +++ b/addons/acodec/sndfile.c @@ -0,0 +1,307 @@ +/* + * Allegro5 External Audio decoder through libsndfile. + * + * Requires libsndfile: http://www.mega-nerd.com/libsndfile/ + * + * author: pkrcel (aka Andrea Provasi) + * + * Revisions: + * 2014-12-30 Initial Release - can only load VOC samples + * 2015-01-03 renamed branch to sndfile + * + */ + +#include "allegro5/allegro.h" +#include "allegro5/allegro_acodec.h" +#include "allegro5/allegro_audio.h" +#include "allegro5/internal/aintern.h" +#include "allegro5/internal/aintern_audio.h" +#include "allegro5/internal/aintern_exitfunc.h" +#include "allegro5/internal/aintern_system.h" +#include "acodec.h" +#include "helper.h" + +#ifndef ALLEGRO_CFG_ACODEC_SNDFILE + #error configuration problem, ALLEGRO_CFG_ACODEC_SNDFILE not set +#endif + +ALLEGRO_DEBUG_CHANNEL("acodec") + +#include + +typedef struct AL_SNDFILE_DATA AL_SNDFILE_DATA; + +struct AL_SNDFILE_DATA { + SNDFILE *sf; + SF_INFO sfinfo; + ALLEGRO_FILE *file; + SF_VIRTUAL_IO al_sd_vio; +}; + + +/* dynamic loading support (Windows only currently) */ +#ifdef ALLEGRO_CFG_ACODEC_SNDFILE_DLL +static void *cva_dll = NULL; +static bool cva_virgin = true; +#endif + +static struct +{ + SNDFILE* (*sf_open_virtual) (SF_VIRTUAL_IO *sfvirtual, int mode, + SF_INFO *sfinfo, void *user_data); +// int (*sf_error) (SNDFILE *); +// const char* (*sf_strerror) (SNDFILE *); +// const char* (*sf_error_number) (int); +// int (*sf_command) (SNDFILE *, int , void *, int ); +// int (*sf_command) (SNDFILE *, int , void *, int ); +// sf_count_t (*sf_seek) (SNDFILE *sndfile, sf_count_t frames, +// int whence); + sf_count_t (*sf_readf_short) (SNDFILE *, short *, sf_count_t ); +// sf_count_t (*sf_writef_short) (SNDFILE *, const short *, sf_count_t ); +// sf_count_t (*sf_readf_int) (SNDFILE *, int *, sf_count_t ); +// sf_count_t (*sf_writef_int) (SNDFILE *, const int *, sf_count_t ); +// sf_count_t (*sf_readf_float) (SNDFILE *, float *, sf_count_t ); +// sf_count_t (*sf_writef_float) (SNDFILE *, const float *, sf_count_t ); +// sf_count_t (*sf_readf_double) (SNDFILE *, double *, sf_count_t ); +// sf_count_t (*sf_writef_double) (SNDFILE *, const double *, sf_count_t ); + + sf_count_t (*sf_read_short) (SNDFILE *, short *, sf_count_t ); +// sf_count_t (*sf_write_short) (SNDFILE *, const short *, sf_count_t ); +// sf_count_t (*sf_read_int) (SNDFILE *, int *, sf_count_t ); +// sf_count_t (*sf_write_int) (SNDFILE *, const int *, sf_count_t ); +// sf_count_t (*sf_read_float) (SNDFILE *, float *, sf_count_t ); +// sf_count_t (*sf_write_float) (SNDFILE *, const float *, sf_count_t ) ; +// sf_count_t (*sf_read_double) (SNDFILE *, double *, sf_count_t ); +// sf_count_t (*sf_write_double) (SNDFILE *, const double *, sf_count_t ); + + int (*sf_close) (SNDFILE *); +} lib; + + +#ifdef ALLEGRO_CFG_ACODEC_SNDFILE_DLL +static void shutdown_dynlib(void) +{ + if (cva_dll) { + _al_close_library(cva_dll); + cva_dll = NULL; + cva_virgin = true; + } +} +#endif + + +static bool init_dynlib(void) +{ +#ifdef ALLEGRO_CFG_ACODEC_SNDFILE_DLL + if (cva_dll) { + return true; + } + + if (!cva_virgin) { + return false; + } + + cva_virgin = false; + + cva_dll = _al_open_library(ALLEGRO_CFG_ACODEC_SNDFILE_DLL); + if (!cva_dll) { + ALLEGRO_WARN("Could not load " ALLEGRO_CFG_ACODEC_SNDFILE_DLL "\n"); + return false; + } + + _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); + + #define INITSYM(x) \ + do \ + { \ + lib.x = _al_import_symbol(cva_dll, #x); \ + if (lib.x == 0) { \ + ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ + return false; \ + } \ + } while(0) +#else + #define INITSYM(x) (lib.x = (x)) +#endif + + memset(&lib, 0, sizeof(lib)); + + INITSYM(sf_open_virtual); + INITSYM(sf_readf_short); + INITSYM(sf_read_short); + INITSYM(sf_close); + + return true; + +#undef INITSYM +} + +/* + * Providing SF_VIRTUAL_IO environment + * these functions have to be passed later to sf_open_virtual + * For mor information: + * + */ +static sf_count_t _al_sf_vio_get_filelen(void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; + return (sf_count_t)al_fsize(f); +} + +static sf_count_t _al_sf_vio_seek (sf_count_t offset, int whence, void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; + + switch(whence) { + case SEEK_SET: whence = ALLEGRO_SEEK_SET; break; + case SEEK_CUR: whence = ALLEGRO_SEEK_CUR; break; + case SEEK_END: whence = ALLEGRO_SEEK_END; break; + } + if (!al_fseek(f, offset, whence)) { + return -1; + } else { + return (sf_count_t)al_ftell(f); + } +} + +static sf_count_t _al_sf_vio_read(void *ptr, sf_count_t count, void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; + size_t nrbytes = 0; + + nrbytes = al_fread(f, ptr, count); + + return nrbytes; +} + +/* + * This is not implemented, current release does not save samples. + * And the implementation SHOULD NOT save streams or samples with sndfile. + * This is because a choice should be made on the format saving + * and standard WAV saving is already available in the library. + */ +static sf_count_t _al_sf_vio_write(const void *ptr, sf_count_t count, void *user_data){ + return 0; +} + +static sf_count_t _al_sf_vio_tell(void *user_data){ + ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; + sf_count_t ret = 0; + + ret = al_ftell(f); + if (ret == -1) + return -1; + + return ret; +} + + +ALLEGRO_SAMPLE *_al_load_sndfile(const char *filename) +{ + ALLEGRO_FILE *f; + ALLEGRO_SAMPLE *spl; + ASSERT(filename); + + ALLEGRO_INFO("Loading sample %s.\n", filename); + f = al_fopen(filename, "rb"); + if (!f) { + ALLEGRO_WARN("Failed reading %s.\n", filename); + return NULL; + } + + spl = _al_load_sndfile_f(f); + + al_fclose(f); + + return spl; +} + + +ALLEGRO_SAMPLE *_al_load_sndfile_f(ALLEGRO_FILE *file) +{ + /* NOTE: The decoding library libsndfile returns "whatever we want" + * and is transparent to the user. + * To conform to other acodec handlers, we'll use 16-bit "short" an no other + * format as the 16Bit PCM data seems to be the most commonly supported. + * + * The decoding library uses the native endian format of the host, so no need + * to check current endianess. + */ + + const int word_size = 2; /* constant stands for 16-bit */ + + short *buffer; /* the actual PCM data buffer */ + ALLEGRO_SAMPLE *sample; + int channels; + long samplerate; + long total_samples; + long total_size; /* unsure about how I handle this */ + AL_SNDFILE_DATA al_sd; + long read; + + if (!init_dynlib()) { + return NULL; + } + + /* Initialize the sndfile object we pass to the decoder*/ + memset(&al_sd, 0, sizeof(al_sd)); + al_sd.al_sd_vio.get_filelen = _al_sf_vio_get_filelen; + al_sd.al_sd_vio.read = _al_sf_vio_read; + al_sd.al_sd_vio.write = _al_sf_vio_write; + al_sd.al_sd_vio.seek = _al_sf_vio_seek; + al_sd.al_sd_vio.tell = _al_sf_vio_tell; + al_sd.file = file; + + + /* Need to open the file first to get the parameters + * + * TODO: inser proper error handling, even thou the ALLEGRO_FILE should + * already have been properly handled by the caller + * + */ + + al_sd.sf = lib.sf_open_virtual(&al_sd.al_sd_vio, SFM_READ, + &al_sd.sfinfo, al_sd.file); + + channels = al_sd.sfinfo.channels; + samplerate = al_sd.sfinfo.samplerate; + total_samples = al_sd.sfinfo.frames; + + total_size = total_samples * channels * word_size; + + ALLEGRO_DEBUG("channels %d\n", channels); + ALLEGRO_DEBUG("word_size %d\n", word_size); + ALLEGRO_DEBUG("rate %ld\n", samplerate); + ALLEGRO_DEBUG("total_samples %ld\n", total_samples); + ALLEGRO_DEBUG("total_size %ld\n", total_size); + + buffer = al_malloc(total_size); + if (!buffer) { + return NULL; + } + + /* + * libsndfile allows us to read all the buffer in "frames". + * Given that 'total_size' is correct, there should not be any overrun. + */ + read = lib.sf_readf_short(al_sd.sf, buffer, al_sd.sfinfo.frames); + + if (read != al_sd.sfinfo.frames) + ALLEGRO_DEBUG("Voc Decoder: read %l bytes for %llu samples\n", + read, al_sd.sfinfo.frames); + + sample = al_create_sample(buffer, total_samples, samplerate, + _al_word_size_to_depth_conf(word_size), + _al_count_to_channel_conf(channels), true); + + if (!sample) { + al_free(buffer); + } + + lib.sf_close(al_sd.sf); + + return sample; +} + +/* + * TODO: + * Should also provide a STREAM LOADER implementation. + * + */ diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index bdc91b6353..5e6aaa8d20 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -1,208 +1,224 @@ /* * Allegro5 Creative Voice Audio Reader. * - * Requires libsndfile + * Loosely based on A4 voc loader and tightly based on specs of the soundblaster + * hardware programming manual: + * + * also specs are available at + * section 11.5 + * + * List of VOC audio codecs suported: + * supported 0x0000 8-bit unsigned PCM + * 0x0001 Creative 8-bit to 4-bit ADPCM *HW implemented on the SB + * 0x0002 Creative 8-bit to 3-bit ADPCM *HW implemented on the SB + * 0x0003 Creative 8-bit to 2-bit ADPCM *HW implemented on the SB + * supported 0x0004 16-bit signed PCM + * + * these are unsupported and present only in VOC files version 1.20 and above + * 0x0006 CCITT a-Law * not really used + * 0x0007 CCITT u-Law * not really used + * 0x0200 Creative 16-bit to 4-bit ADPCM *HW implemented on the SB + * * * author: pkrcel (aka Andrea Provasi) * * Revisions: - * 2014-12-30 Initial Release - can only load samples - * 2015-01-02 Source check and complete test with ex_acodec - * First pull requesto to Allegro Dev team + * 2015-01-03 Source derived from previous sndfile implementation + * cleaned up and put decoder into voc.c */ -#include "allegro5/allegro.h" -#include "allegro5/allegro_acodec.h" +//#include + #include "allegro5/allegro_audio.h" -#include "allegro5/internal/aintern.h" #include "allegro5/internal/aintern_audio.h" -#include "allegro5/internal/aintern_exitfunc.h" -#include "allegro5/internal/aintern_system.h" #include "acodec.h" #include "helper.h" -#ifndef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE - #error configuration problem, ALLEGRO_CFG_ACODEC_CREATIVE_VOICE not set -#endif - -ALLEGRO_DEBUG_CHANNEL("acodec") - -#include - -typedef struct AL_SNDFILE_DATA AL_SNDFILE_DATA; - -struct AL_SNDFILE_DATA { - SNDFILE *sf; - SF_INFO sfinfo; - ALLEGRO_FILE *file; - SF_VIRTUAL_IO al_sd_vio; -}; - - -/* dynamic loading support (Windows only currently) */ -#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL -static void *cva_dll = NULL; -static bool cva_virgin = true; -#endif -static struct -{ - SNDFILE* (*sf_open_virtual) (SF_VIRTUAL_IO *sfvirtual, int mode, - SF_INFO *sfinfo, void *user_data); -// int (*sf_error) (SNDFILE *); -// const char* (*sf_strerror) (SNDFILE *); -// const char* (*sf_error_number) (int); -// int (*sf_command) (SNDFILE *, int , void *, int ); +ALLEGRO_DEBUG_CHANNEL("voc") // will this work? - sf_count_t (*sf_readf_short) (SNDFILE *, short *, sf_count_t ); -// sf_count_t (*sf_writef_short) (SNDFILE *, const short *, sf_count_t ); -// sf_count_t (*sf_readf_int) (SNDFILE *, int *, sf_count_t ); -// sf_count_t (*sf_writef_int) (SNDFILE *, const int *, sf_count_t ); -// sf_count_t (*sf_readf_float) (SNDFILE *, float *, sf_count_t ); -// sf_count_t (*sf_writef_float) (SNDFILE *, const float *, sf_count_t ); -// sf_count_t (*sf_readf_double) (SNDFILE *, double *, sf_count_t ); -// sf_count_t (*sf_writef_double) (SNDFILE *, const double *, sf_count_t ); - sf_count_t (*sf_read_short) (SNDFILE *, short *, sf_count_t ); -// sf_count_t (*sf_write_short) (SNDFILE *, const short *, sf_count_t ); -// sf_count_t (*sf_read_int) (SNDFILE *, int *, sf_count_t ); -// sf_count_t (*sf_write_int) (SNDFILE *, const int *, sf_count_t ); -// sf_count_t (*sf_read_float) (SNDFILE *, float *, sf_count_t ); -// sf_count_t (*sf_write_float) (SNDFILE *, const float *, sf_count_t ) ; -// sf_count_t (*sf_read_double) (SNDFILE *, double *, sf_count_t ); -// sf_count_t (*sf_write_double) (SNDFILE *, const double *, sf_count_t ); - int (*sf_close) (SNDFILE *); -} lib; - - -#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL -static void shutdown_dynlib(void) -{ - if (cva_dll) { - _al_close_library(cva_dll); - cva_dll = NULL; - cva_virgin = true; - } -} -#endif +typedef struct AL_VOC_DATA AL_VOC_DATA; +struct AL_VOC_DATA { + ALLEGRO_FILE *file; + size_t datapos; + int samplerate; + short bits; /* 8 (unsigned char) or 16 (signed short) */ + short channels; /* 1 (mono) or 2 (stereo) */ + int sample_size; /* channels * bits/8 */ + int samples; /* # of samples. size = samples * sample_size */ +}; -static bool init_dynlib(void) -{ -#ifdef ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL - if (cva_dll) { - return true; +/* + * Fills in a VOC data header with information obtained by opening an + * caller-provided ALLEGRO_FILE. + * The datapos index will be the first data byte of the first data block which + * contains ACTUAL data. + */ +static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ + AL_VOC_DATA vocdata; + char hdrbuf[0x16]; + size_t readcount = 0; + uint8_t blocktype = 0; + uint16_t timeconstant = 0; + uint32_t blocklength = 0; //length is stored in 3 bites LE, gd byteorder. + uint16_t format = 0; // can be 16-bit in Blocktype 9 (voc version > 1.20 + uint16_t vocversion = 0; + uint16_t checkver = 0; // must be 1's complement of vocversion + 0x1234 + + if (!fp){ + ALLEGRO_WARN("voc_open: Failed opening ALLEGRO_FILE"); + return NULL; + }; + + /* init VOC data */ + memset(&vocdata, 0, sizeof(vocdata)); + memset(hdrbuf, 0, sizeof(hdrbuf)); + vocdata.file = fp; + + /* Begin checking the Header info */ + readcount = al_fread(fp, hdrbuf, 0x16); + if (readcount != 0x16 /*shorter header*/ + || !memcmp(hdrbuf, "Creative Voice File"+ 0x1A, 0x14) /*wrong id */ + || !memcmp(hdrbuf[0x15], 0x001A, 0x2)){ /*wrong offset */ + ALLEGRO_WARN("voc_open: File does not appear to be a valid VOC file"); + return NULL; } - if (!cva_virgin) { - return false; + al_fread(fp, &vocversion, 2); + if (vocversion != 0x10A || vocversion != 0x114){ // known ver 1.10 -1.20 + ALLEGRO_WARN("voc_open: File is of unknown version"); + return NULL; } - - cva_virgin = false; - - cva_dll = _al_open_library(ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL); - if (!cva_dll) { - ALLEGRO_WARN("Could not load " ALLEGRO_CFG_ACODEC_CREATIVE_VOICE_DLL "\n"); - return false; + /* checksum version check */ + al_fread(fp, checkver, 2); + if (checkver != !vocversion + 0x1234){ + ALLEGRO_WARN("voc_open: Bad VOC Version Identification Number"); + return NULL; } - - _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); - - #define INITSYM(x) \ - do \ - { \ - lib.x = _al_import_symbol(cva_dll, #x); \ - if (lib.x == 0) { \ - ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ - return false; \ - } \ - } while(0) -#else - #define INITSYM(x) (lib.x = (x)) -#endif - - memset(&lib, 0, sizeof(lib)); - - INITSYM(sf_open_virtual); - INITSYM(sf_readf_short); - INITSYM(sf_read_short); - INITSYM(sf_close); - - return true; - -#undef INITSYM -} - -/* - * Providing SF_VIRTUAL_IO environment - * these functions have to be passed later to sf_open_virtual - * For mor information: - * - */ -static sf_count_t _al_sf_vio_get_filelen(void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; - return (sf_count_t)al_fsize(f); -} - -static sf_count_t _al_sf_vio_seek (sf_count_t offset, int whence, void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; - - switch(whence) { - case SEEK_SET: whence = ALLEGRO_SEEK_SET; break; - case SEEK_CUR: whence = ALLEGRO_SEEK_CUR; break; - case SEEK_END: whence = ALLEGRO_SEEK_END; break; + /* + * We're at che first datablock, we shall check type and set all the relevant + * info in the vocdata structure, including finally the datapos index to the + * first valid data byte. + */ + uint8_t x = 0; + al_fread(fp, &blocktype, 1); + al_fread(fp, &blocklength, 2); + al_fread(fp, &x, 1); + blocklength += x<<16; + switch (blocktype){ + case 1: + /* blocktype 1 is the most basic header with 1byte format, time + * constant and length equal to (datalength + 2). + */ + blocklength -= 2; + al_fread(fp, &timeconstant, 1); + al_fread(fp, &format,1); + vocdata.bits = 8; /* only possible codec for Blocktype 1 */ + vocdata.channels = 1; /* block 1 alone means MONO */ + vocdata.samplerate = 1000000 / (256 - timeconstant); + vocdata.sample_size = 1; /* or better: 1 * 8 / 8 */ + /* + * Expected number of samples is at LEAST what is in this block. + * IIF lentgh 0xFFF there will be a following blocktype 2. + * We will deal with this later in load_voc. + */ + vocdata.samples = blocklength / vocdata.sample_size; + vocdata.datapos = al_ftell(fp); + break; + case 8: + /* Blocktype 8 is enhanced data block (mainly for Stereo samples I + * guess) that precedes a Blocktype 1, of which the sound infor have + * to be ignored. + * We skip to the end of the following Blocktype 1 once we get all the + * required header info. + */ + if (blocklength != 4){ + ALLEGRO_WARN("voc_open: Got opening Blocktype 8 of wrong length"); + return NULL; + } + al_fread(fp, &timeconstant, 2); /* here a full 16bit word is stored */ + al_fread(fp, &format,1); + al_fread(fp, &vocdata.channels, 1); + vocdata.channels += 1; /* was 0 for mono, 1 for stereo */ + vocdata.bits = 8; /* only possible codec for Blocktype 8 */ + vocdata.samplerate = 1000000 / (256 - timeconstant); + vocdata.samplerate /= vocdata.channels; + vocdata.sample_size = vocdata.channels * vocdata.bits / 8; + /* + * Now following there is a blocktype 1 which tells us the length of + * the data block and all other info are discarded. + */ + al_fread(fp, &blocktype, 1); + if (blocktype != 1){ + ALLEGRO_WARN("voc_open: Blocktype following type 8 is not 1"); + return NULL; + } + al_fread(fp, &blocklength, 2); + al_fread(fp, &x, 1); + blocklength += x<<16; + blocklength -=2; + al_fread(fp, &x, 2); /* just skip 2 bytes, we're now at datapos */ + vocdata.samples = blocklength / vocdata.sample_size; + vocdata.datapos = al_ftell(fp); + break; + case 9: + /* + * BLocktype 9 is available only for VOC version 1.20 and above + * Deals with 16-bit codecs and stereo and is richier than blocktype 1 + * or the combo 8+1. + * length is 12 bytes more than actual data. + */ + blocklength -= 12; + al_fread(fp, &vocdata.samplerate, 4); /* actual samplerate */ + al_fread(fp, &vocdata.bits, 1); /* actual bits after compression */ + al_fread(fp, &vocdata.channels, 1); /* actual channels */ + al_fread(fp, &format, 2); + if ((vocdata.bits != 8 && vocdata.bit != 16) || + (format != 0 && format != 4)){ + ALLEGRO_WARN("voc_open: unsupported CODEC in voc data"); + return NULL; + } + al_fread(fp, &x, 4); /* just skip 4 reserved bytes */ + vocdata.datapos = al_ftell(fp); + break; + case 2: // + case 3: // these cases are just + case 4: // ignored in this span + case 5: // and wll not return a + case 6: // valid VOC data. + case 7: // + default: + ALLEGRO_WARN("voc_open: opening Block is of unsupported type"); + return NULL; + break; } - if (!al_fseek(f, offset, whence)) { - return -1; - } else { - return (sf_count_t)al_ftell(f); - } -} - -static sf_count_t _al_sf_vio_read(void *ptr, sf_count_t count, void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; - size_t nrbytes = 0; - - nrbytes = al_fread(f, ptr, count); - - return nrbytes; + return vocdata; } -/* - * This is not yet implemented, current release does not save samples. - * - */ -static sf_count_t _al_sf_vio_write(const void *ptr, sf_count_t count, void *user_data){ - return 0; -} - -static sf_count_t _al_sf_vio_tell(void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; - sf_count_t ret = 0; - - ret = al_ftell(f); - if (ret == -1) - return -1; +static bool voc_close(AL_VOC_DATA *vocdata){ + ASSERT(vocdata); - return ret; + al_free(vocdata); } -ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename) +ALLEGRO_SAMPLE *_al_load_voc(const char *filename) { ALLEGRO_FILE *f; ALLEGRO_SAMPLE *spl; ASSERT(filename); - ALLEGRO_INFO("Loading sample %s.\n", filename); + ALLEGRO_INFO("Loading VOC sample %s.\n", filename); f = al_fopen(filename, "rb"); if (!f) { ALLEGRO_WARN("Failed reading %s.\n", filename); return NULL; } - spl = _al_load_creative_voice_f(f); + spl = _al_load_voc_f(f); al_fclose(f); @@ -210,86 +226,95 @@ ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename) } -ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *file) +ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) { /* NOTE: The decoding library libsndfile returns "whatever we want" * and is transparent to the user. - * To conform to other acodec handlers, we'll use 16-bit "short" an no other - * format as the 16Bit PCM data seems to be the most commonly supported. - * - * The decoding library uses the native endian format of the host, so no need - * to check curent endianess. */ + AL_VOC_DATA vocdata; + memset(&vocdata, 0, sizeof(vocdata)); - const int word_size = 2; /* constant stands for 16-bit */ + ALLEGRO_SAMPLE *sample = NULL; + size_t pos = 0; /* where to write in the buffer */ + size_t read = 0; /*bytes read during last operation */ + char* buffer; - short *buffer; /* the actual PCM data buffer */ - ALLEGRO_SAMPLE *sample; - int channels; - long samplerate; - long total_samples; - long total_size; /* unsure about how I handle this */ - AL_SNDFILE_DATA al_sd; - long read; - - if (!init_dynlib()) { - return NULL; - } - - /* Initialize the sndfile object we pass to the decoder*/ - memset(&al_sd, 0, sizeof(al_sd)); - al_sd.al_sd_vio.get_filelen = _al_sf_vio_get_filelen; - al_sd.al_sd_vio.read = _al_sf_vio_read; - al_sd.al_sd_vio.write = _al_sf_vio_write; - al_sd.al_sd_vio.seek = _al_sf_vio_seek; - al_sd.al_sd_vio.tell = _al_sf_vio_tell; - al_sd.file = file; - - - /* Need to open the file first to get the parameters - * - * TODO: inser proper error handling, even thou the ALLEGRO_FILE should - * already have been properly handled by the caller - * + /* + * Open file and populate VOC DATA, then create a buffer for the number of + * samples of the frst block. + * Iterate on the following blocks till EOF or terminator block */ + vocdata = voc_open(file); + if (!vocdata) return NULL; - al_sd.sf = lib.sf_open_virtual(&al_sd.al_sd_vio, SFM_READ, - &al_sd.sfinfo, al_sd.file); - - channels = al_sd.sfinfo.channels; - samplerate = al_sd.sfinfo.samplerate; - total_samples = al_sd.sfinfo.frames; - - total_size = total_samples * channels * word_size; - ALLEGRO_DEBUG("channels %d\n", channels); - ALLEGRO_DEBUG("word_size %d\n", word_size); - ALLEGRO_DEBUG("rate %ld\n", samplerate); - ALLEGRO_DEBUG("total_samples %ld\n", total_samples); - ALLEGRO_DEBUG("total_size %ld\n", total_size); + ALLEGRO_DEBUG("channels %d\n", vocdata.channels); + ALLEGRO_DEBUG("word_size %d\n", vocdata.sample_size); + ALLEGRO_DEBUG("rate %ld\n", vocdata.samplerate); + ALLEGRO_DEBUG("first_block_samples %ld\n", vocdata.samples); + ALLEGRO_DEBUG("first_block_size %ld\n", vocdata.samples * vocdata.sample_size); - buffer = al_malloc(total_size); + /* + * Let's allocate at least the first block's bytes; + */ + buffer = al_malloc(vocdata.samples * vocdata.sample_size); if (!buffer) { return NULL; } - /* - * libsndfile allows us to read all the buffer in "frames". - * Given that 'total_size' is correct, there should not be any overrun. - * NOTE: 'read' is unused by it might be beneficial to add a sanity check - * having it compared to the total frames actually read and the expected. + * We now need to iterate over data blocks till either we hit end of file + * or we find a terminator block. */ - read = lib.sf_readf_short(al_sd.sf, buffer, al_sd.sfinfo.frames); - - sample = al_create_sample(buffer, total_samples, samplerate, - _al_word_size_to_depth_conf(word_size), - _al_count_to_channel_conf(channels), true); - - if (!sample) { - al_free(buffer); + size_t bytestoread = vocdata.samples * vocdata.sample_size; + bool endofvoc = false; + while(!endofvoc && !al_feof(vocdata.file)){ + long blocktype =0; + read = al_fread(vocdata.file, buffer, bytestoread); + pos += read; + al_fread(vocdata.file, &blocktype, 1); /* read next block type */ + if (al_feof(vocdata.file)) break; + switch (blocktype){ + case 0: /* we found a terminator block */ + endofvoc = true; + break; + case 2: /*we found a continuation block: unlikely but handled */ + bytestoread = 0; + al_fread(vocdata.file, &bytestoread, 2); + al_fread(vocdata.file, &x, 1); + bytestoread += x<<16; + /* increase subsequently storage */ + buffer = al_realloc(buffer, sizeof(buffer) + bytestoread); + break; + case 1: // we found a NEW data block starter, I assume this is wrong + case 8: // and let the so far read sample data correctly in the + case 9: // already allocated buffer. + endofvoc = true; + break; + case 3: /* we found a pause block */ + case 4: /* we found a marker block */ + case 5: /* we found an ASCII c-string block */ + case 6: /* we found a repeat block */ + case 7: /* we found an end repeat block */ + /* all these blocks will be skipped */ + uint32_t len = 0, x = 0; + al_fread(vocdata.file, &len, 2); + al_fread(vocdata.file, &x, 1); + len += x<<16; // this is the length what's left to skip */ + for (int ii = 0; ii < len ; ++ii){ + al_fgetc(vocdata.file); + } + bytestoread = 0; //should let safely heck for the next block */ + break; + default: + break; + } } - lib.sf_close(al_sd.sf); + sample = al_create_sample(buffer, pos, vocdata.samplerate, + _al_word_size_to_depth_conf(vocdata.sample_size), + _al_count_to_channel_conf(vocdata.channels), true); + if (!sample) + al_free(buffer); return sample; } From 71b696e822c829a646ceeee6fc72691907a3bccc Mon Sep 17 00:00:00 2001 From: pkrcel Date: Mon, 5 Jan 2015 01:34:52 +0100 Subject: [PATCH 05/18] fixed some stupid syntax bugs and validated voc loader against samples from Master of Orion. --- addons/acodec/acodec.c | 4 ++ addons/acodec/acodec.h | 4 +- addons/acodec/voc.c | 126 ++++++++++++++++++++++------------------- 3 files changed, 75 insertions(+), 59 deletions(-) diff --git a/addons/acodec/acodec.c b/addons/acodec/acodec.c index c0050362ae..374a33d79e 100644 --- a/addons/acodec/acodec.c +++ b/addons/acodec/acodec.c @@ -26,6 +26,10 @@ bool al_init_acodec_addon(void) ret &= al_register_sample_saver_f(".wav", _al_save_wav_f); ret &= al_register_audio_stream_loader_f(".wav", _al_load_wav_audio_stream_f); + /* buil-in VOC loader */ + ret &= al_register_sample_loader(".voc", _al_load_voc); + ret &= al_register_sample_loader_f(".voc", _al_load_voc_f); + #ifdef ALLEGRO_CFG_ACODEC_FLAC ret &= al_register_sample_loader(".flac", _al_load_flac); ret &= al_register_audio_stream_loader(".flac", _al_load_flac_audio_stream); diff --git a/addons/acodec/acodec.h b/addons/acodec/acodec.h index 3ad26852d1..dd9e246652 100644 --- a/addons/acodec/acodec.h +++ b/addons/acodec/acodec.h @@ -17,8 +17,8 @@ bool _al_save_wav_f(ALLEGRO_FILE *pf, ALLEGRO_SAMPLE *spl); * should not implement streams since it's unlikely this container * will ever be used as such. */ -ALLEGRO_SAMPLE *_al_load_creative_voice(const char *filename); -ALLEGRO_SAMPLE *_al_load_creative_voice_f(ALLEGRO_FILE *fp); +ALLEGRO_SAMPLE *_al_load_voc(const char *filename); +ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *fp); #ifdef ALLEGRO_CFG_ACODEC_FLAC diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 5e6aaa8d20..5271c7da07 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -58,7 +58,7 @@ struct AL_VOC_DATA { * contains ACTUAL data. */ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ - AL_VOC_DATA vocdata; + AL_VOC_DATA *vocdata; char hdrbuf[0x16]; size_t readcount = 0; uint8_t blocktype = 0; @@ -74,27 +74,28 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ }; /* init VOC data */ - memset(&vocdata, 0, sizeof(vocdata)); + vocdata = al_malloc(sizeof(AL_VOC_DATA)); + memset(vocdata, 0, sizeof(*vocdata)); memset(hdrbuf, 0, sizeof(hdrbuf)); - vocdata.file = fp; + vocdata->file = fp; /* Begin checking the Header info */ readcount = al_fread(fp, hdrbuf, 0x16); if (readcount != 0x16 /*shorter header*/ || !memcmp(hdrbuf, "Creative Voice File"+ 0x1A, 0x14) /*wrong id */ - || !memcmp(hdrbuf[0x15], 0x001A, 0x2)){ /*wrong offset */ + || !memcmp(hdrbuf+0x15 , "" + 0x001A, 0x2)){ /*wrong offset */ ALLEGRO_WARN("voc_open: File does not appear to be a valid VOC file"); return NULL; } al_fread(fp, &vocversion, 2); - if (vocversion != 0x10A || vocversion != 0x114){ // known ver 1.10 -1.20 + if (vocversion != 0x10A && vocversion != 0x114){ // known ver 1.10 -1.20 ALLEGRO_WARN("voc_open: File is of unknown version"); return NULL; } /* checksum version check */ - al_fread(fp, checkver, 2); - if (checkver != !vocversion + 0x1234){ + al_fread(fp, &checkver, 2); + if (checkver != ~vocversion + 0x1234){ ALLEGRO_WARN("voc_open: Bad VOC Version Identification Number"); return NULL; } @@ -116,17 +117,17 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ blocklength -= 2; al_fread(fp, &timeconstant, 1); al_fread(fp, &format,1); - vocdata.bits = 8; /* only possible codec for Blocktype 1 */ - vocdata.channels = 1; /* block 1 alone means MONO */ - vocdata.samplerate = 1000000 / (256 - timeconstant); - vocdata.sample_size = 1; /* or better: 1 * 8 / 8 */ + vocdata->bits = 8; /* only possible codec for Blocktype 1 */ + vocdata->channels = 1; /* block 1 alone means MONO */ + vocdata->samplerate = 1000000 / (256 - timeconstant); + vocdata->sample_size = 1; /* or better: 1 * 8 / 8 */ /* * Expected number of samples is at LEAST what is in this block. * IIF lentgh 0xFFF there will be a following blocktype 2. * We will deal with this later in load_voc. */ - vocdata.samples = blocklength / vocdata.sample_size; - vocdata.datapos = al_ftell(fp); + vocdata->samples = blocklength / vocdata->sample_size; + vocdata->datapos = al_ftell(fp); break; case 8: /* Blocktype 8 is enhanced data block (mainly for Stereo samples I @@ -141,12 +142,12 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ } al_fread(fp, &timeconstant, 2); /* here a full 16bit word is stored */ al_fread(fp, &format,1); - al_fread(fp, &vocdata.channels, 1); - vocdata.channels += 1; /* was 0 for mono, 1 for stereo */ - vocdata.bits = 8; /* only possible codec for Blocktype 8 */ - vocdata.samplerate = 1000000 / (256 - timeconstant); - vocdata.samplerate /= vocdata.channels; - vocdata.sample_size = vocdata.channels * vocdata.bits / 8; + al_fread(fp, &vocdata->channels, 1); + vocdata->channels += 1; /* was 0 for mono, 1 for stereo */ + vocdata->bits = 8; /* only possible codec for Blocktype 8 */ + vocdata->samplerate = 1000000 / (256 - timeconstant); + vocdata->samplerate /= vocdata->channels; + vocdata->sample_size = vocdata->channels * vocdata->bits / 8; /* * Now following there is a blocktype 1 which tells us the length of * the data block and all other info are discarded. @@ -161,8 +162,8 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ blocklength += x<<16; blocklength -=2; al_fread(fp, &x, 2); /* just skip 2 bytes, we're now at datapos */ - vocdata.samples = blocklength / vocdata.sample_size; - vocdata.datapos = al_ftell(fp); + vocdata->samples = blocklength / vocdata->sample_size; + vocdata->datapos = al_ftell(fp); break; case 9: /* @@ -172,17 +173,17 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ * length is 12 bytes more than actual data. */ blocklength -= 12; - al_fread(fp, &vocdata.samplerate, 4); /* actual samplerate */ - al_fread(fp, &vocdata.bits, 1); /* actual bits after compression */ - al_fread(fp, &vocdata.channels, 1); /* actual channels */ + al_fread(fp, &vocdata->samplerate, 4); /* actual samplerate */ + al_fread(fp, &vocdata->bits, 1); /* actual bits after compression */ + al_fread(fp, &vocdata->channels, 1); /* actual channels */ al_fread(fp, &format, 2); - if ((vocdata.bits != 8 && vocdata.bit != 16) || + if ((vocdata->bits != 8 && vocdata->bits != 16) || (format != 0 && format != 4)){ ALLEGRO_WARN("voc_open: unsupported CODEC in voc data"); return NULL; } al_fread(fp, &x, 4); /* just skip 4 reserved bytes */ - vocdata.datapos = al_ftell(fp); + vocdata->datapos = al_ftell(fp); break; case 2: // case 3: // these cases are just @@ -198,7 +199,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ return vocdata; } -static bool voc_close(AL_VOC_DATA *vocdata){ +static void voc_close(AL_VOC_DATA *vocdata){ ASSERT(vocdata); al_free(vocdata); @@ -231,8 +232,9 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) /* NOTE: The decoding library libsndfile returns "whatever we want" * and is transparent to the user. */ - AL_VOC_DATA vocdata; - memset(&vocdata, 0, sizeof(vocdata)); + AL_VOC_DATA *vocdata; + vocdata = al_malloc(sizeof(AL_VOC_DATA)); + memset(vocdata, 0, sizeof(vocdata)); ALLEGRO_SAMPLE *sample = NULL; size_t pos = 0; /* where to write in the buffer */ @@ -248,16 +250,16 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) if (!vocdata) return NULL; - ALLEGRO_DEBUG("channels %d\n", vocdata.channels); - ALLEGRO_DEBUG("word_size %d\n", vocdata.sample_size); - ALLEGRO_DEBUG("rate %ld\n", vocdata.samplerate); - ALLEGRO_DEBUG("first_block_samples %ld\n", vocdata.samples); - ALLEGRO_DEBUG("first_block_size %ld\n", vocdata.samples * vocdata.sample_size); + ALLEGRO_DEBUG("channels %d\n", vocdata->channels); + ALLEGRO_DEBUG("word_size %d\n", vocdata->sample_size); + ALLEGRO_DEBUG("rate %d\n", vocdata->samplerate); + ALLEGRO_DEBUG("first_block_samples %d\n", vocdata->samples); + ALLEGRO_DEBUG("first_block_size %d\n", vocdata->samples * vocdata->sample_size); /* * Let's allocate at least the first block's bytes; */ - buffer = al_malloc(vocdata.samples * vocdata.sample_size); + buffer = al_malloc(vocdata->samples * vocdata->sample_size); if (!buffer) { return NULL; } @@ -265,54 +267,62 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) * We now need to iterate over data blocks till either we hit end of file * or we find a terminator block. */ - size_t bytestoread = vocdata.samples * vocdata.sample_size; + size_t bytestoread = vocdata->samples * vocdata->sample_size; bool endofvoc = false; - while(!endofvoc && !al_feof(vocdata.file)){ - long blocktype =0; - read = al_fread(vocdata.file, buffer, bytestoread); + while(!endofvoc && !al_feof(vocdata->file)){ + uint32_t blocktype =0; + uint32_t x = 0, len = 0; + read = al_fread(vocdata->file, buffer, bytestoread); pos += read; - al_fread(vocdata.file, &blocktype, 1); /* read next block type */ - if (al_feof(vocdata.file)) break; + al_fread(vocdata->file, &blocktype, 1); /* read next block type */ + if (al_feof(vocdata->file)) break; switch (blocktype){ - case 0: /* we found a terminator block */ + case 0:{ /* we found a terminator block */ endofvoc = true; break; - case 2: /*we found a continuation block: unlikely but handled */ + } + case 2:{ /*we found a continuation block: unlikely but handled */ + x = 0; bytestoread = 0; - al_fread(vocdata.file, &bytestoread, 2); - al_fread(vocdata.file, &x, 1); + al_fread(vocdata->file, &bytestoread, 2); + al_fread(vocdata->file, &x, 1); bytestoread += x<<16; /* increase subsequently storage */ buffer = al_realloc(buffer, sizeof(buffer) + bytestoread); break; + } case 1: // we found a NEW data block starter, I assume this is wrong case 8: // and let the so far read sample data correctly in the - case 9: // already allocated buffer. + case 9:{ // already allocated buffer. endofvoc = true; break; + } case 3: /* we found a pause block */ case 4: /* we found a marker block */ case 5: /* we found an ASCII c-string block */ case 6: /* we found a repeat block */ - case 7: /* we found an end repeat block */ + case 7:{ /* we found an end repeat block */ /* all these blocks will be skipped */ - uint32_t len = 0, x = 0; - al_fread(vocdata.file, &len, 2); - al_fread(vocdata.file, &x, 1); + len = 0; + x = 0; + al_fread(vocdata->file, &len, 2); + al_fread(vocdata->file, &x, 1); len += x<<16; // this is the length what's left to skip */ - for (int ii = 0; ii < len ; ++ii){ - al_fgetc(vocdata.file); + int ii; + for (ii = 0; ii < len ; ++ii){ + al_fgetc(vocdata->file); } bytestoread = 0; //should let safely heck for the next block */ break; + } default: break; } } - sample = al_create_sample(buffer, pos, vocdata.samplerate, - _al_word_size_to_depth_conf(vocdata.sample_size), - _al_count_to_channel_conf(vocdata.channels), true); + sample = al_create_sample(buffer, pos, vocdata->samplerate, + _al_word_size_to_depth_conf(vocdata->sample_size), + _al_count_to_channel_conf(vocdata->channels), true); if (!sample) al_free(buffer); @@ -320,7 +330,9 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) } /* - * TODO: - * Should also provide a STREAM implementation. + * A stream implementation is not provided since it is unlikely that this format + * will ever be used as such. + * Things may change thou. * */ + From 44148532db5f1622a8782bb11f0c30605a348dae Mon Sep 17 00:00:00 2001 From: pkrcel Date: Thu, 8 Jan 2015 19:02:48 +0100 Subject: [PATCH 06/18] Removed sndfile support from branch. --- addons/acodec/CMakeLists.txt | 58 ------- addons/acodec/sndfile.c | 307 ----------------------------------- 2 files changed, 365 deletions(-) delete mode 100644 addons/acodec/sndfile.c diff --git a/addons/acodec/CMakeLists.txt b/addons/acodec/CMakeLists.txt index 57ebdc75b2..3ac9e609f6 100644 --- a/addons/acodec/CMakeLists.txt +++ b/addons/acodec/CMakeLists.txt @@ -4,7 +4,6 @@ option(WANT_FLAC "Enable FLAC support" on) option(WANT_VORBIS "Enable Ogg Vorbis support using libvorbis" on) option(WANT_TREMOR "Enable Ogg Vorbis support using Tremor" off) option(WANT_MODAUDIO "Enable MOD Audio support" on) -option(WANT_SNDFILE_AUDIO "Enable libsndfile as External Audio " off) option(WANT_ACODEC_DYNAMIC_LOAD "Enable DLL loading in acodec (Windows)" on) #-----------------------------------------------------------------------------# @@ -262,63 +261,6 @@ if(SUPPORT_VORBIS) endif() endif(SUPPORT_VORBIS) -# -# SNDFILE (libsndfile) audio -# adds support for libsndfile offline decoder. -# - -if(WANT_SNDFILE_AUDIO) - find_package(SNDFILE) - if(SNDFILE_FOUND) - set(CMAKE_REQUIRED_INCLUDES ${SNDFILE_INCLUDE_DIR}) - set(CMAKE_REQUIRED_LIBRARIES ${SNDFILE_LIBRARIES}) - check_c_source_compiles(" - #include - int main(void) - { - char buffer[128]; - sf_command(NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)); - return 0; - }" - SNDFILE_COMPILES) - set(CMAKE_REQUIRED_INCLUDES) - set(CMAKE_REQUIRED_LIBRARIES) - if(SNDFILE_COMPILES) - set(SUPPORT_SNDFILE_AUDIO 1) - else() - message("libsndfile compile test FAILED") - endif(SNDFILE_COMPILES) - endif(SNDFILE_FOUND) - if(NOT SUPPORT_SNDFILE_AUDIO) - message("WARNING: SNDFILE not found or compile test failed," - "disabling support. ") - endif(NOT SUPPORT_SNDFILE_AUDIO) -endif(WANT_SNDFILE_AUDIO) - -if(SUPPORT_SNDFILE_AUDIO) - include_directories(SYSTEM ${SNDFILE_INCLUDE_DIR}) - set(ALLEGRO_CFG_ACODEC_SNDFILE 1) - list(APPEND ACODEC_SOURCES sndfile.c) - - list(APPEND ACODEC_INCLUDE_DIRECTORIES ${SNDFILE_INCLUDE_DIR}) - - if(WIN32 AND WANT_ACODEC_DYNAMIC_LOAD) - if(SNDFILE_LIBRARY MATCHES "${WIN32_STATIC_LIB_REGEX}") - message("WARNING: Dynamic loading will be disabled for SNDFILE" - " as static library was found: ${SNDFILE_LIBRARY};" - "NOTE: licensing of SNDFILE (under LGLPL v2/v3) requires " - "this code to be licended under GPL. " - "for more information: http://www.mega-nerd.com/SNDFILE/#Licensing") - else() - get_dll_name(${SNDFILE_LIBRARY} ALLEGRO_CFG_ACODEC_SNDFILE_DLL) - endif() - endif() - - if(NOT ALLEGRO_CFG_ACODEC_SNDFILE_DLL) - list(APPEND ACODEC_LIBRARIES ${SNDFILE_LIBRARIES}) - endif() -endif() - configure_file( allegro5/internal/aintern_acodec_cfg.h.cmake ${CMAKE_BINARY_DIR}/include/allegro5/internal/aintern_acodec_cfg.h diff --git a/addons/acodec/sndfile.c b/addons/acodec/sndfile.c deleted file mode 100644 index cb140e1d23..0000000000 --- a/addons/acodec/sndfile.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Allegro5 External Audio decoder through libsndfile. - * - * Requires libsndfile: http://www.mega-nerd.com/libsndfile/ - * - * author: pkrcel (aka Andrea Provasi) - * - * Revisions: - * 2014-12-30 Initial Release - can only load VOC samples - * 2015-01-03 renamed branch to sndfile - * - */ - -#include "allegro5/allegro.h" -#include "allegro5/allegro_acodec.h" -#include "allegro5/allegro_audio.h" -#include "allegro5/internal/aintern.h" -#include "allegro5/internal/aintern_audio.h" -#include "allegro5/internal/aintern_exitfunc.h" -#include "allegro5/internal/aintern_system.h" -#include "acodec.h" -#include "helper.h" - -#ifndef ALLEGRO_CFG_ACODEC_SNDFILE - #error configuration problem, ALLEGRO_CFG_ACODEC_SNDFILE not set -#endif - -ALLEGRO_DEBUG_CHANNEL("acodec") - -#include - -typedef struct AL_SNDFILE_DATA AL_SNDFILE_DATA; - -struct AL_SNDFILE_DATA { - SNDFILE *sf; - SF_INFO sfinfo; - ALLEGRO_FILE *file; - SF_VIRTUAL_IO al_sd_vio; -}; - - -/* dynamic loading support (Windows only currently) */ -#ifdef ALLEGRO_CFG_ACODEC_SNDFILE_DLL -static void *cva_dll = NULL; -static bool cva_virgin = true; -#endif - -static struct -{ - SNDFILE* (*sf_open_virtual) (SF_VIRTUAL_IO *sfvirtual, int mode, - SF_INFO *sfinfo, void *user_data); -// int (*sf_error) (SNDFILE *); -// const char* (*sf_strerror) (SNDFILE *); -// const char* (*sf_error_number) (int); -// int (*sf_command) (SNDFILE *, int , void *, int ); -// int (*sf_command) (SNDFILE *, int , void *, int ); -// sf_count_t (*sf_seek) (SNDFILE *sndfile, sf_count_t frames, -// int whence); - sf_count_t (*sf_readf_short) (SNDFILE *, short *, sf_count_t ); -// sf_count_t (*sf_writef_short) (SNDFILE *, const short *, sf_count_t ); -// sf_count_t (*sf_readf_int) (SNDFILE *, int *, sf_count_t ); -// sf_count_t (*sf_writef_int) (SNDFILE *, const int *, sf_count_t ); -// sf_count_t (*sf_readf_float) (SNDFILE *, float *, sf_count_t ); -// sf_count_t (*sf_writef_float) (SNDFILE *, const float *, sf_count_t ); -// sf_count_t (*sf_readf_double) (SNDFILE *, double *, sf_count_t ); -// sf_count_t (*sf_writef_double) (SNDFILE *, const double *, sf_count_t ); - - sf_count_t (*sf_read_short) (SNDFILE *, short *, sf_count_t ); -// sf_count_t (*sf_write_short) (SNDFILE *, const short *, sf_count_t ); -// sf_count_t (*sf_read_int) (SNDFILE *, int *, sf_count_t ); -// sf_count_t (*sf_write_int) (SNDFILE *, const int *, sf_count_t ); -// sf_count_t (*sf_read_float) (SNDFILE *, float *, sf_count_t ); -// sf_count_t (*sf_write_float) (SNDFILE *, const float *, sf_count_t ) ; -// sf_count_t (*sf_read_double) (SNDFILE *, double *, sf_count_t ); -// sf_count_t (*sf_write_double) (SNDFILE *, const double *, sf_count_t ); - - int (*sf_close) (SNDFILE *); -} lib; - - -#ifdef ALLEGRO_CFG_ACODEC_SNDFILE_DLL -static void shutdown_dynlib(void) -{ - if (cva_dll) { - _al_close_library(cva_dll); - cva_dll = NULL; - cva_virgin = true; - } -} -#endif - - -static bool init_dynlib(void) -{ -#ifdef ALLEGRO_CFG_ACODEC_SNDFILE_DLL - if (cva_dll) { - return true; - } - - if (!cva_virgin) { - return false; - } - - cva_virgin = false; - - cva_dll = _al_open_library(ALLEGRO_CFG_ACODEC_SNDFILE_DLL); - if (!cva_dll) { - ALLEGRO_WARN("Could not load " ALLEGRO_CFG_ACODEC_SNDFILE_DLL "\n"); - return false; - } - - _al_add_exit_func(shutdown_dynlib, "shutdown_dynlib"); - - #define INITSYM(x) \ - do \ - { \ - lib.x = _al_import_symbol(cva_dll, #x); \ - if (lib.x == 0) { \ - ALLEGRO_ERROR("undefined symbol in lib structure: " #x "\n"); \ - return false; \ - } \ - } while(0) -#else - #define INITSYM(x) (lib.x = (x)) -#endif - - memset(&lib, 0, sizeof(lib)); - - INITSYM(sf_open_virtual); - INITSYM(sf_readf_short); - INITSYM(sf_read_short); - INITSYM(sf_close); - - return true; - -#undef INITSYM -} - -/* - * Providing SF_VIRTUAL_IO environment - * these functions have to be passed later to sf_open_virtual - * For mor information: - * - */ -static sf_count_t _al_sf_vio_get_filelen(void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; - return (sf_count_t)al_fsize(f); -} - -static sf_count_t _al_sf_vio_seek (sf_count_t offset, int whence, void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE*)user_data; - - switch(whence) { - case SEEK_SET: whence = ALLEGRO_SEEK_SET; break; - case SEEK_CUR: whence = ALLEGRO_SEEK_CUR; break; - case SEEK_END: whence = ALLEGRO_SEEK_END; break; - } - if (!al_fseek(f, offset, whence)) { - return -1; - } else { - return (sf_count_t)al_ftell(f); - } -} - -static sf_count_t _al_sf_vio_read(void *ptr, sf_count_t count, void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; - size_t nrbytes = 0; - - nrbytes = al_fread(f, ptr, count); - - return nrbytes; -} - -/* - * This is not implemented, current release does not save samples. - * And the implementation SHOULD NOT save streams or samples with sndfile. - * This is because a choice should be made on the format saving - * and standard WAV saving is already available in the library. - */ -static sf_count_t _al_sf_vio_write(const void *ptr, sf_count_t count, void *user_data){ - return 0; -} - -static sf_count_t _al_sf_vio_tell(void *user_data){ - ALLEGRO_FILE *f = (ALLEGRO_FILE *)user_data; - sf_count_t ret = 0; - - ret = al_ftell(f); - if (ret == -1) - return -1; - - return ret; -} - - -ALLEGRO_SAMPLE *_al_load_sndfile(const char *filename) -{ - ALLEGRO_FILE *f; - ALLEGRO_SAMPLE *spl; - ASSERT(filename); - - ALLEGRO_INFO("Loading sample %s.\n", filename); - f = al_fopen(filename, "rb"); - if (!f) { - ALLEGRO_WARN("Failed reading %s.\n", filename); - return NULL; - } - - spl = _al_load_sndfile_f(f); - - al_fclose(f); - - return spl; -} - - -ALLEGRO_SAMPLE *_al_load_sndfile_f(ALLEGRO_FILE *file) -{ - /* NOTE: The decoding library libsndfile returns "whatever we want" - * and is transparent to the user. - * To conform to other acodec handlers, we'll use 16-bit "short" an no other - * format as the 16Bit PCM data seems to be the most commonly supported. - * - * The decoding library uses the native endian format of the host, so no need - * to check current endianess. - */ - - const int word_size = 2; /* constant stands for 16-bit */ - - short *buffer; /* the actual PCM data buffer */ - ALLEGRO_SAMPLE *sample; - int channels; - long samplerate; - long total_samples; - long total_size; /* unsure about how I handle this */ - AL_SNDFILE_DATA al_sd; - long read; - - if (!init_dynlib()) { - return NULL; - } - - /* Initialize the sndfile object we pass to the decoder*/ - memset(&al_sd, 0, sizeof(al_sd)); - al_sd.al_sd_vio.get_filelen = _al_sf_vio_get_filelen; - al_sd.al_sd_vio.read = _al_sf_vio_read; - al_sd.al_sd_vio.write = _al_sf_vio_write; - al_sd.al_sd_vio.seek = _al_sf_vio_seek; - al_sd.al_sd_vio.tell = _al_sf_vio_tell; - al_sd.file = file; - - - /* Need to open the file first to get the parameters - * - * TODO: inser proper error handling, even thou the ALLEGRO_FILE should - * already have been properly handled by the caller - * - */ - - al_sd.sf = lib.sf_open_virtual(&al_sd.al_sd_vio, SFM_READ, - &al_sd.sfinfo, al_sd.file); - - channels = al_sd.sfinfo.channels; - samplerate = al_sd.sfinfo.samplerate; - total_samples = al_sd.sfinfo.frames; - - total_size = total_samples * channels * word_size; - - ALLEGRO_DEBUG("channels %d\n", channels); - ALLEGRO_DEBUG("word_size %d\n", word_size); - ALLEGRO_DEBUG("rate %ld\n", samplerate); - ALLEGRO_DEBUG("total_samples %ld\n", total_samples); - ALLEGRO_DEBUG("total_size %ld\n", total_size); - - buffer = al_malloc(total_size); - if (!buffer) { - return NULL; - } - - /* - * libsndfile allows us to read all the buffer in "frames". - * Given that 'total_size' is correct, there should not be any overrun. - */ - read = lib.sf_readf_short(al_sd.sf, buffer, al_sd.sfinfo.frames); - - if (read != al_sd.sfinfo.frames) - ALLEGRO_DEBUG("Voc Decoder: read %l bytes for %llu samples\n", - read, al_sd.sfinfo.frames); - - sample = al_create_sample(buffer, total_samples, samplerate, - _al_word_size_to_depth_conf(word_size), - _al_count_to_channel_conf(channels), true); - - if (!sample) { - al_free(buffer); - } - - lib.sf_close(al_sd.sf); - - return sample; -} - -/* - * TODO: - * Should also provide a STREAM LOADER implementation. - * - */ From 70266345224f94c1371944d9a2d3e6158a5faf48 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Thu, 8 Jan 2015 22:01:13 +0100 Subject: [PATCH 07/18] Cleaned up voc.c of all ISO C90-related warnings and tightened some code lines. Removed and polished the comments. --- addons/acodec/voc.c | 64 ++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 5271c7da07..6613c2de1a 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -8,16 +8,16 @@ * section 11.5 * * List of VOC audio codecs suported: - * supported 0x0000 8-bit unsigned PCM - * 0x0001 Creative 8-bit to 4-bit ADPCM *HW implemented on the SB - * 0x0002 Creative 8-bit to 3-bit ADPCM *HW implemented on the SB - * 0x0003 Creative 8-bit to 2-bit ADPCM *HW implemented on the SB - * supported 0x0004 16-bit signed PCM + * supported 0x0000 8-bit unsigned PCM + * 0x0001 Creative 8-bit to 4-bit ADPCM *HW implemented on the SB + * 0x0002 Creative 8-bit to 3-bit ADPCM *HW implemented on the SB + * 0x0003 Creative 8-bit to 2-bit ADPCM *HW implemented on the SB + * supported 0x0004 16-bit signed PCM * * these are unsupported and present only in VOC files version 1.20 and above - * 0x0006 CCITT a-Law * not really used - * 0x0007 CCITT u-Law * not really used - * 0x0200 Creative 16-bit to 4-bit ADPCM *HW implemented on the SB + * 0x0006 CCITT a-Law * not really used + * 0x0007 CCITT u-Law * not really used + * 0x0200 Creative 16-bit to 4-bit ADPCM *HW implemented on the SB * * * author: pkrcel (aka Andrea Provasi) @@ -25,9 +25,10 @@ * Revisions: * 2015-01-03 Source derived from previous sndfile implementation * cleaned up and put decoder into voc.c + * 2015-01-08 Clean up ISO C90 related warnings and tried to get + * a consistent code style and removed some comments. */ -//#include #include "allegro5/allegro_audio.h" #include "allegro5/internal/aintern_audio.h" @@ -35,7 +36,7 @@ #include "helper.h" -ALLEGRO_DEBUG_CHANNEL("voc") // will this work? +ALLEGRO_DEBUG_CHANNEL("voc") @@ -61,13 +62,17 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ AL_VOC_DATA *vocdata; char hdrbuf[0x16]; size_t readcount = 0; + uint8_t blocktype = 0; + uint8_t x = 0; + uint16_t timeconstant = 0; - uint32_t blocklength = 0; //length is stored in 3 bites LE, gd byteorder. uint16_t format = 0; // can be 16-bit in Blocktype 9 (voc version > 1.20 uint16_t vocversion = 0; uint16_t checkver = 0; // must be 1's complement of vocversion + 0x1234 + uint32_t blocklength = 0; //length is stored in 3 bites LE, gd byteorder. + if (!fp){ ALLEGRO_WARN("voc_open: Failed opening ALLEGRO_FILE"); return NULL; @@ -83,7 +88,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ readcount = al_fread(fp, hdrbuf, 0x16); if (readcount != 0x16 /*shorter header*/ || !memcmp(hdrbuf, "Creative Voice File"+ 0x1A, 0x14) /*wrong id */ - || !memcmp(hdrbuf+0x15 , "" + 0x001A, 0x2)){ /*wrong offset */ + || !memcmp(hdrbuf+0x15 , "" + 0x001A, 0x2)){ /*wrong offset */ ALLEGRO_WARN("voc_open: File does not appear to be a valid VOC file"); return NULL; } @@ -104,7 +109,6 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ * info in the vocdata structure, including finally the datapos index to the * first valid data byte. */ - uint8_t x = 0; al_fread(fp, &blocktype, 1); al_fread(fp, &blocklength, 2); al_fread(fp, &x, 1); @@ -167,10 +171,10 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ break; case 9: /* - * BLocktype 9 is available only for VOC version 1.20 and above + * Blocktype 9 is available only for VOC version 1.20 and above. * Deals with 16-bit codecs and stereo and is richier than blocktype 1 - * or the combo 8+1. - * length is 12 bytes more than actual data. + * or the BLocktype 8+1 combo + * Length is 12 bytes more than actual data. */ blocklength -= 12; al_fread(fp, &vocdata->samplerate, 4); /* actual samplerate */ @@ -229,18 +233,18 @@ ALLEGRO_SAMPLE *_al_load_voc(const char *filename) ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) { - /* NOTE: The decoding library libsndfile returns "whatever we want" - * and is transparent to the user. - */ - AL_VOC_DATA *vocdata; - vocdata = al_malloc(sizeof(AL_VOC_DATA)); - memset(vocdata, 0, sizeof(vocdata)); + AL_VOC_DATA *vocdata; ALLEGRO_SAMPLE *sample = NULL; size_t pos = 0; /* where to write in the buffer */ size_t read = 0; /*bytes read during last operation */ char* buffer; + size_t bytestoread = 0; + bool endofvoc = false; + + vocdata = al_malloc(sizeof(AL_VOC_DATA)); + memset(vocdata, 0, sizeof(*vocdata)); /* * Open file and populate VOC DATA, then create a buffer for the number of * samples of the frst block. @@ -267,8 +271,7 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) * We now need to iterate over data blocks till either we hit end of file * or we find a terminator block. */ - size_t bytestoread = vocdata->samples * vocdata->sample_size; - bool endofvoc = false; + bytestoread = vocdata->samples * vocdata->sample_size; while(!endofvoc && !al_feof(vocdata->file)){ uint32_t blocktype =0; uint32_t x = 0, len = 0; @@ -303,12 +306,12 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) case 6: /* we found a repeat block */ case 7:{ /* we found an end repeat block */ /* all these blocks will be skipped */ + unsigned int ii; len = 0; x = 0; al_fread(vocdata->file, &len, 2); al_fread(vocdata->file, &x, 1); len += x<<16; // this is the length what's left to skip */ - int ii; for (ii = 0; ii < len ; ++ii){ al_fgetc(vocdata->file); } @@ -322,17 +325,18 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) sample = al_create_sample(buffer, pos, vocdata->samplerate, _al_word_size_to_depth_conf(vocdata->sample_size), - _al_count_to_channel_conf(vocdata->channels), true); + _al_count_to_channel_conf(vocdata->channels), + true); if (!sample) al_free(buffer); + voc_close(vocdata); + return sample; } /* - * A stream implementation is not provided since it is unlikely that this format - * will ever be used as such. - * Things may change thou. - * + * So far a stream implementation is not provided, since it is deemed unlikely + * that this format will ever be used as such. */ From f36120d937b1dfcca6bdf5a14e097c1aebc08ba8 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 9 Jan 2015 14:57:09 +0100 Subject: [PATCH 08/18] Removed last traces of sndfile support from branch. Thanks Beoran. --- .../internal/aintern_acodec_cfg.h.cmake | 2 -- cmake/FindSndfile.cmake | 28 ------------------- 2 files changed, 30 deletions(-) delete mode 100644 cmake/FindSndfile.cmake diff --git a/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake b/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake index 29c86555eb..fbaab02de7 100644 --- a/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake +++ b/addons/acodec/allegro5/internal/aintern_acodec_cfg.h.cmake @@ -2,11 +2,9 @@ #cmakedefine ALLEGRO_CFG_ACODEC_MODAUDIO #cmakedefine ALLEGRO_CFG_ACODEC_VORBIS #cmakedefine ALLEGRO_CFG_ACODEC_TREMOR -#cmakedefine ALLEGRO_CFG_ACODEC_SNDFILE /* Define if the library should be loaded dynamically. */ #cmakedefine ALLEGRO_CFG_ACODEC_FLAC_DLL "@ALLEGRO_CFG_ACODEC_FLAC_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_DUMB_DLL "@ALLEGRO_CFG_ACODEC_DUMB_DLL@" #cmakedefine ALLEGRO_CFG_ACODEC_VORBISFILE_DLL "@ALLEGRO_CFG_ACODEC_VORBISFILE_DLL@" -#cmakedefine ALLEGRO_CFG_ACODEC_SNDFILE_DLL "@ALLEGRO_CFG_ACODEC_SNDFILE_DLL@" diff --git a/cmake/FindSndfile.cmake b/cmake/FindSndfile.cmake deleted file mode 100644 index ac8a63569d..0000000000 --- a/cmake/FindSndfile.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# - Find sndfile -# Find the native sndfile includes and libraries -# -# SNDFILE_INCLUDE_DIR - where to find sndfile.h, etc. -# SNDFILE_LIBRARIES - List of libraries when using libsndfile. -# SNDFILE_FOUND - True if libsndfile found. - -if(SNDFILE_INCLUDE_DIR) - # Already in cache, be silent - set(SNDFILE_FIND_QUIETLY TRUE) -endif(SNDFILE_INCLUDE_DIR) - -find_path(SNDFILE_INCLUDE_DIR sndfile.h) - -find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1) - -# Handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if -# all listed variables are TRUE. -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SNDFILE DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR) - -if(SNDFILE_FOUND) - set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY}) -else(SNDFILE_FOUND) - set(SNDFILE_LIBRARIES) -endif(SNDFILE_FOUND) - -mark_as_advanced(SNDFILE_INCLUDE_DIR SNDFILE_LIBRARY) From 430ef1882129691b9df58701c8b9c56a4e8ae4b0 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 9 Jan 2015 16:43:38 +0100 Subject: [PATCH 09/18] Removed last bit of sndfile? (I should learn better) --- addons/acodec/acodec.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/addons/acodec/acodec.c b/addons/acodec/acodec.c index 374a33d79e..72cfc17497 100644 --- a/addons/acodec/acodec.c +++ b/addons/acodec/acodec.c @@ -55,17 +55,6 @@ bool al_init_acodec_addon(void) ret &= al_register_audio_stream_loader_f(".ogg", _al_load_ogg_vorbis_audio_stream_f); #endif -#ifdef ALLEGRO_CFG_ACODEC_SNDFILE - /* - * These are here for placeholder on a format actually read by sndfile - */ - ret &= al_register_sample_loader(".aiff", _al_load_sndfile); -// ret &= al_register_audio_stream_loader(".VOC", _al_load_VOC_audio_stream); - - ret &= al_register_sample_loader_f(".aiff", _al_load_sndfile_f); -// ret &= al_register_audio_stream_loader_f(".VOC", _al_load_VOC_audio_stream_f); -#endif - return ret; } From a4ba82336f4ee7729e5f289492c5409e950e3fbe Mon Sep 17 00:00:00 2001 From: pkrcel Date: Sun, 11 Jan 2015 15:02:28 +0100 Subject: [PATCH 10/18] Removed a couple additional warnings about array bounds. --- addons/acodec/voc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 6613c2de1a..130980524f 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -87,8 +87,8 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ /* Begin checking the Header info */ readcount = al_fread(fp, hdrbuf, 0x16); if (readcount != 0x16 /*shorter header*/ - || !memcmp(hdrbuf, "Creative Voice File"+ 0x1A, 0x14) /*wrong id */ - || !memcmp(hdrbuf+0x15 , "" + 0x001A, 0x2)){ /*wrong offset */ + || !memcmp(hdrbuf, "Creative Voice File\0x1A", 0x14) /*wrong id */ + || !memcmp(hdrbuf+0x15 , "\0x00\0x1A", 0x2)){ /*wrong offset */ ALLEGRO_WARN("voc_open: File does not appear to be a valid VOC file"); return NULL; } From 2999d3182f445b24e7bd38888a1a58d86f55af44 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Thu, 15 Jan 2015 23:55:25 +0100 Subject: [PATCH 11/18] Removed yet another bit of SNDFILE implementation in acodec.h --- addons/acodec/acodec.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/addons/acodec/acodec.h b/addons/acodec/acodec.h index dd9e246652..bb6218dfe7 100644 --- a/addons/acodec/acodec.h +++ b/addons/acodec/acodec.h @@ -58,9 +58,6 @@ ALLEGRO_AUDIO_STREAM *_al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples); #endif -#ifdef ALLEGRO_CFG_ACODEC_SNDFILE -ALLEGRO_SAMPLE *_al_load_sndfile(const char *filename); -ALLEGRO_SAMPLE *_al_load_sndfile_f(ALLEGRO_FILE *file); -#endif + #endif From 9a2df625c5100a83514944e700ffd0180b1cb707 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 16 Jan 2015 00:02:51 +0100 Subject: [PATCH 12/18] Hoping to have put a more consistent and Allegro-friendly code-style in voc.c. --- addons/acodec/voc.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 130980524f..9464f9bc17 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -58,7 +58,8 @@ struct AL_VOC_DATA { * The datapos index will be the first data byte of the first data block which * contains ACTUAL data. */ -static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ +static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) +{ AL_VOC_DATA *vocdata; char hdrbuf[0x16]; size_t readcount = 0; @@ -73,7 +74,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ uint32_t blocklength = 0; //length is stored in 3 bites LE, gd byteorder. - if (!fp){ + if (!fp) { ALLEGRO_WARN("voc_open: Failed opening ALLEGRO_FILE"); return NULL; }; @@ -88,19 +89,19 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ readcount = al_fread(fp, hdrbuf, 0x16); if (readcount != 0x16 /*shorter header*/ || !memcmp(hdrbuf, "Creative Voice File\0x1A", 0x14) /*wrong id */ - || !memcmp(hdrbuf+0x15 , "\0x00\0x1A", 0x2)){ /*wrong offset */ + || !memcmp(hdrbuf+0x15 , "\0x00\0x1A", 0x2)) { /*wrong offset */ ALLEGRO_WARN("voc_open: File does not appear to be a valid VOC file"); return NULL; } al_fread(fp, &vocversion, 2); - if (vocversion != 0x10A && vocversion != 0x114){ // known ver 1.10 -1.20 + if (vocversion != 0x10A && vocversion != 0x114) { // known ver 1.10 -1.20 ALLEGRO_WARN("voc_open: File is of unknown version"); return NULL; } /* checksum version check */ al_fread(fp, &checkver, 2); - if (checkver != ~vocversion + 0x1234){ + if (checkver != ~vocversion + 0x1234) { ALLEGRO_WARN("voc_open: Bad VOC Version Identification Number"); return NULL; } @@ -113,7 +114,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ al_fread(fp, &blocklength, 2); al_fread(fp, &x, 1); blocklength += x<<16; - switch (blocktype){ + switch (blocktype) { case 1: /* blocktype 1 is the most basic header with 1byte format, time * constant and length equal to (datalength + 2). @@ -140,7 +141,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ * We skip to the end of the following Blocktype 1 once we get all the * required header info. */ - if (blocklength != 4){ + if (blocklength != 4) { ALLEGRO_WARN("voc_open: Got opening Blocktype 8 of wrong length"); return NULL; } @@ -157,7 +158,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ * the data block and all other info are discarded. */ al_fread(fp, &blocktype, 1); - if (blocktype != 1){ + if (blocktype != 1) { ALLEGRO_WARN("voc_open: Blocktype following type 8 is not 1"); return NULL; } @@ -182,7 +183,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ al_fread(fp, &vocdata->channels, 1); /* actual channels */ al_fread(fp, &format, 2); if ((vocdata->bits != 8 && vocdata->bits != 16) || - (format != 0 && format != 4)){ + (format != 0 && format != 4)) { ALLEGRO_WARN("voc_open: unsupported CODEC in voc data"); return NULL; } @@ -203,7 +204,8 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp){ return vocdata; } -static void voc_close(AL_VOC_DATA *vocdata){ +static void voc_close(AL_VOC_DATA *vocdata) +{ ASSERT(vocdata); al_free(vocdata); @@ -272,14 +274,14 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) * or we find a terminator block. */ bytestoread = vocdata->samples * vocdata->sample_size; - while(!endofvoc && !al_feof(vocdata->file)){ + while(!endofvoc && !al_feof(vocdata->file)) { uint32_t blocktype =0; uint32_t x = 0, len = 0; read = al_fread(vocdata->file, buffer, bytestoread); pos += read; al_fread(vocdata->file, &blocktype, 1); /* read next block type */ if (al_feof(vocdata->file)) break; - switch (blocktype){ + switch (blocktype) { case 0:{ /* we found a terminator block */ endofvoc = true; break; @@ -312,7 +314,7 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) al_fread(vocdata->file, &len, 2); al_fread(vocdata->file, &x, 1); len += x<<16; // this is the length what's left to skip */ - for (ii = 0; ii < len ; ++ii){ + for (ii = 0; ii < len ; ++ii) { al_fgetc(vocdata->file); } bytestoread = 0; //should let safely heck for the next block */ From c828ee3e49b9781e2cdac6df115f136d01ea4351 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 16 Jan 2015 00:07:26 +0100 Subject: [PATCH 13/18] Added Allegro ASCII art into header. --- addons/acodec/voc.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 9464f9bc17..69209e819a 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -1,4 +1,13 @@ -/* +/* ______ ___ ___ + * /\ _ \ /\_ \ /\_ \ + * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ + * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ + * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ + * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ + * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ + * /\____/ + * \_/__/ + * * Allegro5 Creative Voice Audio Reader. * * Loosely based on A4 voc loader and tightly based on specs of the soundblaster @@ -35,11 +44,8 @@ #include "acodec.h" #include "helper.h" - ALLEGRO_DEBUG_CHANNEL("voc") - - typedef struct AL_VOC_DATA AL_VOC_DATA; struct AL_VOC_DATA { @@ -58,6 +64,7 @@ struct AL_VOC_DATA { * The datapos index will be the first data byte of the first data block which * contains ACTUAL data. */ + static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) { AL_VOC_DATA *vocdata; From 20d09f19bc9efcf61229897ade435478b0447d3c Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 16 Jan 2015 00:16:12 +0100 Subject: [PATCH 14/18] Forgot to update revisions, not really useful nowadays with git & Co but still. --- addons/acodec/voc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 69209e819a..a919e083bb 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -36,6 +36,7 @@ * cleaned up and put decoder into voc.c * 2015-01-08 Clean up ISO C90 related warnings and tried to get * a consistent code style and removed some comments. + * 2015-01-15 Corrected style and enriched header. */ From 1a2fc8d8d88b1c269b36dc3820d8bd1a2fa3460a Mon Sep 17 00:00:00 2001 From: pkrcel Date: Fri, 16 Jan 2015 00:29:16 +0100 Subject: [PATCH 15/18] Added "Welcome To Allegro" VOC file in the examples data section. --- examples/data/welcome.voc | Bin 0 -> 24113 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/data/welcome.voc diff --git a/examples/data/welcome.voc b/examples/data/welcome.voc new file mode 100644 index 0000000000000000000000000000000000000000..9ca9012cddc63bd8d5a75527cfad6aeeaa076d10 GIT binary patch literal 24113 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 Date: Fri, 16 Jan 2015 01:02:05 +0100 Subject: [PATCH 16/18] Forgot to commit the added line in examples/Cmakelists.txt for example VOC file copy. --- examples/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 97171af065..70a435772b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -70,6 +70,7 @@ set(DATA_TTF set(DATA_AUDIO welcome.wav + welcome.voc ) set(DATA_SHADERS From 6b8f0056addaaa2e5ed2d47b67bf0267fa6e0d4c Mon Sep 17 00:00:00 2001 From: pkrcel Date: Sat, 17 Jan 2015 00:07:14 +0100 Subject: [PATCH 17/18] Inserted return check on all al_read through an evil macro. --- addons/acodec/voc.c | 56 ++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index a919e083bb..9d70ab476c 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -47,6 +47,8 @@ ALLEGRO_DEBUG_CHANNEL("voc") + + typedef struct AL_VOC_DATA AL_VOC_DATA; struct AL_VOC_DATA { @@ -66,6 +68,13 @@ struct AL_VOC_DATA { * contains ACTUAL data. */ +#define READNBYTES(f, data, n, retv) \ + if (al_fread(f, &data, n) != n) { \ + ALLEGRO_WARN("voc_open: Bad Number of bytes read in last operation"); \ + return retv; \ + } + + static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) { AL_VOC_DATA *vocdata; @@ -118,9 +127,9 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) * info in the vocdata structure, including finally the datapos index to the * first valid data byte. */ - al_fread(fp, &blocktype, 1); - al_fread(fp, &blocklength, 2); - al_fread(fp, &x, 1); + READNBYTES(fp, blocktype, 1, NULL); + READNBYTES(fp, blocklength, 2, NULL); + READNBYTES(fp, x, 1, NULL); blocklength += x<<16; switch (blocktype) { case 1: @@ -128,8 +137,8 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) * constant and length equal to (datalength + 2). */ blocklength -= 2; - al_fread(fp, &timeconstant, 1); - al_fread(fp, &format,1); + READNBYTES(fp, timeconstant, 1, NULL); + READNBYTES(fp, format, 1, NULL); vocdata->bits = 8; /* only possible codec for Blocktype 1 */ vocdata->channels = 1; /* block 1 alone means MONO */ vocdata->samplerate = 1000000 / (256 - timeconstant); @@ -153,9 +162,9 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) ALLEGRO_WARN("voc_open: Got opening Blocktype 8 of wrong length"); return NULL; } - al_fread(fp, &timeconstant, 2); /* here a full 16bit word is stored */ - al_fread(fp, &format,1); - al_fread(fp, &vocdata->channels, 1); + READNBYTES(fp, timeconstant, 2, NULL); + READNBYTES(fp, format, 1, NULL); + READNBYTES(fp, vocdata->channels, 1, NULL); vocdata->channels += 1; /* was 0 for mono, 1 for stereo */ vocdata->bits = 8; /* only possible codec for Blocktype 8 */ vocdata->samplerate = 1000000 / (256 - timeconstant); @@ -165,16 +174,16 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) * Now following there is a blocktype 1 which tells us the length of * the data block and all other info are discarded. */ - al_fread(fp, &blocktype, 1); + READNBYTES(fp, blocktype, 1, NULL); if (blocktype != 1) { ALLEGRO_WARN("voc_open: Blocktype following type 8 is not 1"); return NULL; } - al_fread(fp, &blocklength, 2); - al_fread(fp, &x, 1); + READNBYTES(fp, blocklength, 2, NULL); + READNBYTES(fp, x, 1, NULL); blocklength += x<<16; blocklength -=2; - al_fread(fp, &x, 2); /* just skip 2 bytes, we're now at datapos */ + READNBYTES(fp, x, 2, NULL); vocdata->samples = blocklength / vocdata->sample_size; vocdata->datapos = al_ftell(fp); break; @@ -186,16 +195,17 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) * Length is 12 bytes more than actual data. */ blocklength -= 12; - al_fread(fp, &vocdata->samplerate, 4); /* actual samplerate */ - al_fread(fp, &vocdata->bits, 1); /* actual bits after compression */ - al_fread(fp, &vocdata->channels, 1); /* actual channels */ - al_fread(fp, &format, 2); + READNBYTES(fp, vocdata->samplerate, 4, NULL); // actual samplerate + READNBYTES(fp, vocdata->bits, 1, NULL); // actual bits + // after compression + READNBYTES(fp, vocdata->channels, 1, NULL); // actual channels + READNBYTES(fp, format, 2, NULL); if ((vocdata->bits != 8 && vocdata->bits != 16) || (format != 0 && format != 4)) { ALLEGRO_WARN("voc_open: unsupported CODEC in voc data"); return NULL; } - al_fread(fp, &x, 4); /* just skip 4 reserved bytes */ + READNBYTES(fp, x, 4, NULL); // just skip 4 reserved bytes vocdata->datapos = al_ftell(fp); break; case 2: // @@ -287,7 +297,7 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) uint32_t x = 0, len = 0; read = al_fread(vocdata->file, buffer, bytestoread); pos += read; - al_fread(vocdata->file, &blocktype, 1); /* read next block type */ + READNBYTES(vocdata->file, blocktype, 1, NULL); // read next block type if (al_feof(vocdata->file)) break; switch (blocktype) { case 0:{ /* we found a terminator block */ @@ -297,8 +307,8 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) case 2:{ /*we found a continuation block: unlikely but handled */ x = 0; bytestoread = 0; - al_fread(vocdata->file, &bytestoread, 2); - al_fread(vocdata->file, &x, 1); + READNBYTES(vocdata->file, bytestoread, 2, NULL); + READNBYTES(vocdata->file, x, 1, NULL); bytestoread += x<<16; /* increase subsequently storage */ buffer = al_realloc(buffer, sizeof(buffer) + bytestoread); @@ -319,13 +329,13 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) unsigned int ii; len = 0; x = 0; - al_fread(vocdata->file, &len, 2); - al_fread(vocdata->file, &x, 1); + READNBYTES(vocdata->file, len, 2, NULL); + READNBYTES(vocdata->file, x, 1, NULL); len += x<<16; // this is the length what's left to skip */ for (ii = 0; ii < len ; ++ii) { al_fgetc(vocdata->file); } - bytestoread = 0; //should let safely heck for the next block */ + bytestoread = 0; //should let safely check for the next block */ break; } default: From 069b68b936295d2db688f3234bf93cc00fc23726 Mon Sep 17 00:00:00 2001 From: pkrcel Date: Sat, 17 Jan 2015 22:22:39 +0100 Subject: [PATCH 18/18] Corrected some minor style issues. --- addons/acodec/voc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/acodec/voc.c b/addons/acodec/voc.c index 9d70ab476c..5cbd811b10 100644 --- a/addons/acodec/voc.c +++ b/addons/acodec/voc.c @@ -81,10 +81,10 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) char hdrbuf[0x16]; size_t readcount = 0; - uint8_t blocktype = 0; + uint8_t blocktype = 0; uint8_t x = 0; - uint16_t timeconstant = 0; + uint16_t timeconstant = 0; uint16_t format = 0; // can be 16-bit in Blocktype 9 (voc version > 1.20 uint16_t vocversion = 0; uint16_t checkver = 0; // must be 1's complement of vocversion + 0x1234 @@ -94,7 +94,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) if (!fp) { ALLEGRO_WARN("voc_open: Failed opening ALLEGRO_FILE"); return NULL; - }; + } /* init VOC data */ vocdata = al_malloc(sizeof(AL_VOC_DATA)); @@ -123,7 +123,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) return NULL; } /* - * We're at che first datablock, we shall check type and set all the relevant + * We're at the first datablock, we shall check type and set all the relevant * info in the vocdata structure, including finally the datapos index to the * first valid data byte. */ @@ -182,7 +182,7 @@ static AL_VOC_DATA *voc_open(ALLEGRO_FILE *fp) READNBYTES(fp, blocklength, 2, NULL); READNBYTES(fp, x, 1, NULL); blocklength += x<<16; - blocklength -=2; + blocklength -= 2; READNBYTES(fp, x, 2, NULL); vocdata->samples = blocklength / vocdata->sample_size; vocdata->datapos = al_ftell(fp); @@ -293,7 +293,7 @@ ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) */ bytestoread = vocdata->samples * vocdata->sample_size; while(!endofvoc && !al_feof(vocdata->file)) { - uint32_t blocktype =0; + uint32_t blocktype = 0; uint32_t x = 0, len = 0; read = al_fread(vocdata->file, buffer, bytestoread); pos += read;