mirror of
https://github.com/libretro/RetroArch
synced 2025-02-28 12:40:23 +00:00
Added support for loading 8 and 16 bps, mono/stereo, uncompressed PCM wave files
This commit is contained in:
parent
bcfbf46e5a
commit
b65e16d39d
173
libretro-common/formats/wav/rwav.c
Normal file
173
libretro-common/formats/wav/rwav.c
Normal file
@ -0,0 +1,173 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rbmp.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.
|
||||
*/
|
||||
|
||||
/* Modified version of stb_image's BMP sources. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h> /* ptrdiff_t on osx */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <formats/rwav.h>
|
||||
|
||||
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);
|
||||
}
|
97
libretro-common/include/formats/rwav.h
Normal file
97
libretro-common/include/formats/rwav.h
Normal file
@ -0,0 +1,97 @@
|
||||
/* Copyright (C) 2010-2015 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rbmp.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 <stdint.h>
|
||||
|
||||
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
|
Loading…
x
Reference in New Issue
Block a user