Replaced my simple wave loader with rxi's
This commit is contained in:
42
src/source.c
42
src/source.c
@@ -9,16 +9,52 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
|
#include "filesystem.h"
|
||||||
#include "lib/dmt/dmt.h"
|
#include "lib/dmt/dmt.h"
|
||||||
#include "wavefile.h"
|
#include "wav.h"
|
||||||
|
|
||||||
|
|
||||||
char const* source_init(source_t *self, char const* filename) {
|
char const* source_init(source_t *self, char const* filename) {
|
||||||
return wavefile_load(self, filename);
|
int fileSize;
|
||||||
|
void *waveData = filesystem_read(filename, &fileSize);
|
||||||
|
|
||||||
|
char const *err = NULL;
|
||||||
|
wav_t wav;
|
||||||
|
int res = wav_read(&wav, waveData, fileSize);
|
||||||
|
|
||||||
|
if(res != WAV_ESUCCESS) {
|
||||||
|
err = wav_strerror(res);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wav.bitdepth != 16) {
|
||||||
|
err = "Invalid Audio Format (only 16 Bit supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wav.samplerate != 22050) {
|
||||||
|
err = "Invalid Audio Format (only 22050Hz supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wav.channels != 1) {
|
||||||
|
err = "Invalid Audio Format (only mono supported)";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->sampleCount = wav.length;
|
||||||
|
self->data = waveData;
|
||||||
|
self->samples = (int16_t*)wav.data;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
filesystem_free(waveData);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void source_deinit(source_t *self) {
|
void source_deinit(source_t *self) {
|
||||||
dmt_free(self->samples);
|
filesystem_free(self->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int sampleCount;
|
int sampleCount;
|
||||||
int16_t *samples;
|
int16_t *samples;
|
||||||
|
void *data;
|
||||||
} source_t;
|
} source_t;
|
||||||
|
|
||||||
char const* source_init(source_t *self, char const* filename);
|
char const* source_init(source_t *self, char const* filename);
|
||||||
|
|||||||
84
src/wav.c
Normal file
84
src/wav.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 rxi
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "wav.h"
|
||||||
|
|
||||||
|
typedef unsigned short Uint16;
|
||||||
|
typedef unsigned int Uint32;
|
||||||
|
|
||||||
|
|
||||||
|
static const char *findSubChunk(
|
||||||
|
const char *data, size_t len, const char *id, size_t *size
|
||||||
|
) {
|
||||||
|
/* TODO : Error handling on malformed wav file */
|
||||||
|
size_t idLen = strlen(id);
|
||||||
|
const char *p = data + 12;
|
||||||
|
next:
|
||||||
|
*size = *((Uint32*) (p + 4));
|
||||||
|
if (memcmp(p, id, idLen)) {
|
||||||
|
p += 8 + *size;
|
||||||
|
if (p > data + len) return NULL;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
return p + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wav_read(wav_t *w, const void *data, size_t len) {
|
||||||
|
int bitdepth, channels, samplerate, format;
|
||||||
|
size_t sz;
|
||||||
|
const char *p = data;
|
||||||
|
memset(w, 0, sizeof(*w));
|
||||||
|
/* Check header */
|
||||||
|
if (memcmp(p, "RIFF", 4) || memcmp(p + 8, "WAVE", 4)) {
|
||||||
|
return WAV_EBADHEADER;
|
||||||
|
}
|
||||||
|
/* Find fmt subchunk */
|
||||||
|
p = findSubChunk(data, len, "fmt", &sz);
|
||||||
|
if (!p) return WAV_ENOFMT;
|
||||||
|
/* Load fmt info */
|
||||||
|
format = *((Uint16*) (p));
|
||||||
|
channels = *((Uint16*) (p + 2));
|
||||||
|
samplerate = *((Uint32*) (p + 4));
|
||||||
|
bitdepth = *((Uint16*) (p + 14));
|
||||||
|
if (format != 1) {
|
||||||
|
return WAV_ENOSUPPORT;
|
||||||
|
}
|
||||||
|
if (channels == 0 || samplerate == 0 || bitdepth == 0) {
|
||||||
|
return WAV_EBADFMT;
|
||||||
|
}
|
||||||
|
/* Find data subchunk */
|
||||||
|
p = findSubChunk(data, len, "data", &sz);
|
||||||
|
if (!p) return WAV_ENODATA;
|
||||||
|
/* Init wav_t struct */
|
||||||
|
w->data = p;
|
||||||
|
w->samplerate = samplerate;
|
||||||
|
w->channels = channels;
|
||||||
|
w->length = (sz / (bitdepth / 8)) / channels;
|
||||||
|
w->bitdepth = bitdepth;
|
||||||
|
/* Done! */
|
||||||
|
return WAV_ESUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *wav_strerror(int err) {
|
||||||
|
switch (err) {
|
||||||
|
case WAV_ESUCCESS : return "success";
|
||||||
|
case WAV_EFAILURE : return "failure";
|
||||||
|
case WAV_EBADHEADER : return "bad header data";
|
||||||
|
case WAV_EBADFMT : return "bad fmt data";
|
||||||
|
case WAV_ENOFMT : return "missing 'fmt' subchunk";
|
||||||
|
case WAV_ENODATA : return "missing 'data' subchunk";
|
||||||
|
case WAV_ENOSUPPORT : return "unsupported format; "
|
||||||
|
"expected uncompressed PCM";
|
||||||
|
}
|
||||||
|
return "unknown error";
|
||||||
|
}
|
||||||
102
src/wavefile.c
102
src/wavefile.c
@@ -1,102 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2017 Florian Kesseler
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the MIT license. See LICENSE for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "filesystem.h"
|
|
||||||
#include "wavefile.h"
|
|
||||||
#include "source.h"
|
|
||||||
#include "lib/dmt/dmt.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t chunkId;
|
|
||||||
uint32_t chunkSize;
|
|
||||||
uint32_t format;
|
|
||||||
uint32_t subchunk1Id;
|
|
||||||
uint32_t subchunk1Size;
|
|
||||||
uint16_t audioFormat;
|
|
||||||
uint16_t numChannels;
|
|
||||||
uint32_t sampleRate;
|
|
||||||
uint32_t byteRate;
|
|
||||||
uint16_t blockAlign;
|
|
||||||
uint16_t bitsPerSample;
|
|
||||||
uint32_t subchunk2Id;
|
|
||||||
uint32_t subchunk2Size;
|
|
||||||
} waveheader_t;
|
|
||||||
|
|
||||||
#define RIFF_CHUNK_ID 0x46464952
|
|
||||||
#define WAVE_FORMAT 0x45564157
|
|
||||||
#define FORMAT_CHUNK_ID 0x20746d66
|
|
||||||
#define DATA_CHUNK_ID 0x61746164
|
|
||||||
#define FORMAT_CHUNK_SIZE 16
|
|
||||||
#define AUDIO_FORMAT_PCM 1
|
|
||||||
|
|
||||||
|
|
||||||
char const* wavefile_load(source_t *source, char const *filename) {
|
|
||||||
int fileSize;
|
|
||||||
char const *err = 0;
|
|
||||||
uint8_t *waveData = filesystem_read(filename, &fileSize);
|
|
||||||
|
|
||||||
if(waveData == NULL) {
|
|
||||||
err = "Could not read WAV file";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
waveheader_t const* header = (waveheader_t const*)waveData;
|
|
||||||
|
|
||||||
if(header->chunkId != RIFF_CHUNK_ID
|
|
||||||
|| header->format != WAVE_FORMAT
|
|
||||||
|| header->subchunk1Id != FORMAT_CHUNK_ID
|
|
||||||
|| header->subchunk2Id != DATA_CHUNK_ID) {
|
|
||||||
err = "Invalid WAV header";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header->subchunk1Size != FORMAT_CHUNK_SIZE
|
|
||||||
|| header->audioFormat != AUDIO_FORMAT_PCM) {
|
|
||||||
err = "Invalid Audio Format (only PCM supported)";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header->numChannels != 1) {
|
|
||||||
err = "Invalid Audio Format (only 1 channel supported)";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header->sampleRate != 22050) {
|
|
||||||
err = "Invalid Audio Format (only 22050Hz supported)";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header->bitsPerSample != 16) {
|
|
||||||
err = "Invalid Audio Format (only 16 Bit supported)";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header->byteRate != header->sampleRate * header->numChannels * header->bitsPerSample / 8) {
|
|
||||||
err = "Byte rate doesn't match header info";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header->blockAlign != header->numChannels * header->bitsPerSample / 8) {
|
|
||||||
err = "Block alignment doesn't match header info";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fileSize < sizeof(waveheader_t) + header->subchunk2Size) {
|
|
||||||
err = "Short read while reading samples";
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
source->sampleCount = header->subchunk2Size / 2;
|
|
||||||
source->samples = (int16_t*)dmt_malloc(header->subchunk2Size);
|
|
||||||
|
|
||||||
memcpy(source->samples, ((uint8_t*)waveData) + sizeof(waveheader_t), header->subchunk2Size);
|
|
||||||
|
|
||||||
fail:
|
|
||||||
filesystem_free(waveData);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2017 Florian Kesseler
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the MIT license. See LICENSE for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WAVEFILE_H
|
|
||||||
#define WAVEFILE_H
|
|
||||||
|
|
||||||
#include "source.h"
|
|
||||||
|
|
||||||
char const* wavefile_load(source_t *source, char const *filename);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user