diff --git a/libretro-common/formats/wav/rwav.c b/libretro-common/formats/wav/rwav.c new file mode 100644 index 0000000000..9ca9fb2c6b --- /dev/null +++ b/libretro-common/formats/wav/rwav.c @@ -0,0 +1,171 @@ +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (rwav.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include /* ptrdiff_t on osx */ +#include +#include + +#include + +enum +{ + ITER_BEGIN, + ITER_COPY_SAMPLES, + ITER_COPY_SAMPLES_8, + ITER_COPY_SAMPLES_16 +}; + +void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void* buf, size_t size) +{ + iter->out = out; + iter->data = (const uint8_t*)buf; + iter->size = size; + iter->step = ITER_BEGIN; + + out->samples = NULL; +} + +int rwav_iterate(rwav_iterator_t *iter) +{ + rwav_t *rwav = iter->out; + const uint8_t *data = iter->data; + uint16_t *u16; + void *samples; + size_t s; + + switch (iter->step) + { + case ITER_BEGIN: + if (iter->size < 44) + return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */ + + if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F') + return RWAV_ITERATE_ERROR; + + if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E') + return RWAV_ITERATE_ERROR; + + if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ') + return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */ + + if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0) + return RWAV_ITERATE_ERROR; + + if (data[20] != 1 || data[21] != 0) + return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */ + + if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a') + return RWAV_ITERATE_ERROR; + + rwav->bitspersample = data[34] | data[35] << 8; + + if (rwav->bitspersample != 8 && rwav->bitspersample != 16) + return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */ + + rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24; + + if (rwav->subchunk2size > iter->size - 44) + return RWAV_ITERATE_ERROR; /* too few bytes in buffer */ + + samples = malloc(rwav->subchunk2size); + + if (samples == NULL) + return RWAV_ITERATE_ERROR; + + rwav->numchannels = data[22] | data[23] << 8; + rwav->numsamples = rwav->subchunk2size * 8 / rwav->bitspersample / rwav->numchannels; + rwav->samplerate = data[24] | data[25] << 8 | data[26] << 16 | data[27] << 24; + rwav->samples = samples; + + iter->step = ITER_COPY_SAMPLES; + return RWAV_ITERATE_MORE; + + case ITER_COPY_SAMPLES: + iter->i = 0; + + if (rwav->bitspersample == 8) + { + iter->step = ITER_COPY_SAMPLES_8; + + case ITER_COPY_SAMPLES_8: + s = rwav->subchunk2size - iter->i; + + if (s > RWAV_ITERATE_BUF_SIZE) + s = RWAV_ITERATE_BUF_SIZE; + + memcpy((void*)rwav->samples, (void *)(iter->data + 44 + iter->i), s); + printf("copied %lu\n", s); + iter->i += s; + + return iter->i < rwav->subchunk2size ? RWAV_ITERATE_MORE : RWAV_ITERATE_DONE; + } + else + { + iter->step = ITER_COPY_SAMPLES_16; + iter->j = 0; + + case ITER_COPY_SAMPLES_16: + s = rwav->subchunk2size - iter->i; + + if (s > RWAV_ITERATE_BUF_SIZE) + s = RWAV_ITERATE_BUF_SIZE; + + printf("copied %lu\n", s); + u16 = (uint16_t *)rwav->samples; + + while (s != 0) + { + u16[iter->j++] = iter->data[44 + iter->i] | iter->data[45 + iter->i] << 8; + iter->i += 2; + s -= 2; + } + + return iter->i < rwav->subchunk2size ? RWAV_ITERATE_MORE : RWAV_ITERATE_DONE; + } + } + + return RWAV_ITERATE_ERROR; +} + +int rwav_load(rwav_t* out, const void* buf, size_t size) +{ + int res; + rwav_iterator_t iter; + + rwav_init(&iter, out, buf, size); + + do + { + res = rwav_iterate(&iter); + } + while (res == RWAV_ITERATE_MORE); + + return res; +} + +void rwav_free(rwav_t *rwav) +{ + free((void*)rwav->samples); +} diff --git a/libretro-common/include/formats/rwav.h b/libretro-common/include/formats/rwav.h new file mode 100644 index 0000000000..21f197f742 --- /dev/null +++ b/libretro-common/include/formats/rwav.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2010-2015 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (rwav.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_FORMAT_RWAV_H__ +#define __LIBRETRO_SDK_FORMAT_RWAV_H__ + +#include +#include + +RETRO_BEGIN_DECLS + +typedef struct +{ + /* bits per sample */ + int bitspersample; + + /* number of channels */ + int numchannels; + + /* sample rate */ + int samplerate; + + /* number of *samples* */ + size_t numsamples; + + /* number of *bytes* in the pointer below, i.e. numsamples * numchannels * bitspersample/8 */ + size_t subchunk2size; + + /* PCM data */ + const void* samples; +} +rwav_t; + +enum +{ + RWAV_ITERATE_ERROR = -1, + RWAV_ITERATE_MORE = 0, + RWAV_ITERATE_DONE = 1, + + RWAV_ITERATE_BUF_SIZE = 4096 +}; + +typedef struct +{ + /* internal data, don't touch */ + rwav_t *out; + const uint8_t *data; + size_t size; + size_t i, j; + int step; +} +rwav_iterator_t; + +/** + * Initializes the iterator to fill the out structure with data parsed from buf. + */ +void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void* buf, size_t size); + +/** + * Parses a piece of the data. Continue calling as long as it returns RWAV_ITERATE_MORE. + * Stop calling otherwise, and check for errors. If RWAV_ITERATE_DONE is returned, + * the rwav_t structure passed to rwav_init is ready to be used. The iterator does not + * have to be freed. + */ +int rwav_iterate(rwav_iterator_t *iter); + +/** + * Loads the entire data in one go. + */ +int rwav_load(rwav_t* out, const void* buf, size_t size); + +/** + * Frees parsed wave data. + */ +void rwav_free(rwav_t *rwav); + +RETRO_END_DECLS + +#endif