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 <stdint.h>
|
||||
#include "source.h"
|
||||
#include "filesystem.h"
|
||||
#include "lib/dmt/dmt.h"
|
||||
#include "wavefile.h"
|
||||
#include "wav.h"
|
||||
|
||||
|
||||
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) {
|
||||
dmt_free(self->samples);
|
||||
filesystem_free(self->data);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
typedef struct {
|
||||
int sampleCount;
|
||||
int16_t *samples;
|
||||
void *data;
|
||||
} source_t;
|
||||
|
||||
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