changeset 7:634df6435e16

libtest: WAV reader and writer code from opencore-amr-0.1.6/test
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 19 Nov 2022 22:50:08 +0000
parents b2255a5d0519
children d5b888e6a05b
files libtest/wavreader.c libtest/wavreader.h libtest/wavwriter.c libtest/wavwriter.h
diffstat 4 files changed, 347 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtest/wavreader.c	Sat Nov 19 22:50:08 2022 +0000
@@ -0,0 +1,163 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 2009 Martin Storsjo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+
+#include "wavreader.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#define TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+struct wav_reader {
+	FILE *wav;
+	uint32_t data_length;
+
+	int format;
+	int sample_rate;
+	int bits_per_sample;
+	int channels;
+	int byte_rate;
+	int block_align;
+};
+
+static uint32_t read_tag(struct wav_reader* wr) {
+	uint32_t tag = 0;
+	tag = (tag << 8) | fgetc(wr->wav);
+	tag = (tag << 8) | fgetc(wr->wav);
+	tag = (tag << 8) | fgetc(wr->wav);
+	tag = (tag << 8) | fgetc(wr->wav);
+	return tag;
+}
+
+static uint32_t read_int32(struct wav_reader* wr) {
+	uint32_t value = 0;
+	value |= fgetc(wr->wav) <<  0;
+	value |= fgetc(wr->wav) <<  8;
+	value |= fgetc(wr->wav) << 16;
+	value |= fgetc(wr->wav) << 24;
+	return value;
+}
+
+static uint16_t read_int16(struct wav_reader* wr) {
+	uint16_t value = 0;
+	value |= fgetc(wr->wav) << 0;
+	value |= fgetc(wr->wav) << 8;
+	return value;
+}
+
+void* wav_read_open(const char *filename) {
+	struct wav_reader* wr = (struct wav_reader*) malloc(sizeof(*wr));
+	long data_pos = 0;
+	memset(wr, 0, sizeof(*wr));
+
+	wr->wav = fopen(filename, "rb");
+	if (wr->wav == NULL) {
+		free(wr);
+		return NULL;
+	}
+
+	while (1) {
+		uint32_t tag, tag2, length;
+		tag = read_tag(wr);
+		if (feof(wr->wav))
+			break;
+		length = read_int32(wr);
+		if (tag != TAG('R', 'I', 'F', 'F') || length < 4) {
+			fseek(wr->wav, length, SEEK_CUR);
+			continue;
+		}
+		tag2 = read_tag(wr);
+		length -= 4;
+		if (tag2 != TAG('W', 'A', 'V', 'E')) {
+			fseek(wr->wav, length, SEEK_CUR);
+			continue;
+		}
+		// RIFF chunk found, iterate through it
+		while (length >= 8) {
+			uint32_t subtag, sublength;
+			subtag = read_tag(wr);
+			if (feof(wr->wav))
+				break;
+			sublength = read_int32(wr);
+			length -= 8;
+			if (length < sublength)
+				break;
+			if (subtag == TAG('f', 'm', 't', ' ')) {
+				if (sublength < 16) {
+					// Insufficient data for 'fmt '
+					break;
+				}
+				wr->format          = read_int16(wr);
+				wr->channels        = read_int16(wr);
+				wr->sample_rate     = read_int32(wr);
+				wr->byte_rate       = read_int32(wr);
+				wr->block_align     = read_int16(wr);
+				wr->bits_per_sample = read_int16(wr);
+				fseek(wr->wav, sublength - 16, SEEK_CUR);
+			} else if (subtag == TAG('d', 'a', 't', 'a')) {
+				data_pos = ftell(wr->wav);
+				wr->data_length = sublength;
+				fseek(wr->wav, sublength, SEEK_CUR);
+			} else {
+				fseek(wr->wav, sublength, SEEK_CUR);
+			}
+			length -= sublength;
+		}
+		if (length > 0) {
+			// Bad chunk?
+			fseek(wr->wav, length, SEEK_CUR);
+		}
+	}
+	fseek(wr->wav, data_pos, SEEK_SET);
+	return wr;
+}
+
+void wav_read_close(void* obj) {
+	struct wav_reader* wr = (struct wav_reader*) obj;
+	fclose(wr->wav);
+	free(wr);
+}
+
+int wav_get_header(void* obj, int* format, int* channels, int* sample_rate, int* bits_per_sample, unsigned int* data_length) {
+	struct wav_reader* wr = (struct wav_reader*) obj;
+	if (format)
+		*format = wr->format;
+	if (channels)
+		*channels = wr->channels;
+	if (sample_rate)
+		*sample_rate = wr->sample_rate;
+	if (bits_per_sample)
+		*bits_per_sample = wr->bits_per_sample;
+	if (data_length)
+		*data_length = wr->data_length;
+	return wr->format && wr->sample_rate;
+}
+
+int wav_read_data(void* obj, unsigned char* data, unsigned int length) {
+	struct wav_reader* wr = (struct wav_reader*) obj;
+	int n;
+	if (wr->wav == NULL)
+		return -1;
+	if (length > wr->data_length)
+		length = wr->data_length;
+	n = fread(data, 1, length, wr->wav);
+	wr->data_length -= length;
+	return n;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtest/wavreader.h	Sat Nov 19 22:50:08 2022 +0000
@@ -0,0 +1,37 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 2009 Martin Storsjo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+
+#ifndef WAVREADER_H
+#define WAVREADER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void* wav_read_open(const char *filename);
+void wav_read_close(void* obj);
+
+int wav_get_header(void* obj, int* format, int* channels, int* sample_rate, int* bits_per_sample, unsigned int* data_length);
+int wav_read_data(void* obj, unsigned char* data, unsigned int length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtest/wavwriter.c	Sat Nov 19 22:50:08 2022 +0000
@@ -0,0 +1,111 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 2009 Martin Storsjo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+
+#include "wavwriter.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+struct wav_writer {
+	FILE *wav;
+	int data_length;
+
+	int sample_rate;
+	int bits_per_sample;
+	int channels;
+};
+
+static void write_string(struct wav_writer* ww, const char *str) {
+	fputc(str[0], ww->wav);
+	fputc(str[1], ww->wav);
+	fputc(str[2], ww->wav);
+	fputc(str[3], ww->wav);
+}
+
+static void write_int32(struct wav_writer* ww, int value) {
+	fputc((value >>  0) & 0xff, ww->wav);
+	fputc((value >>  8) & 0xff, ww->wav);
+	fputc((value >> 16) & 0xff, ww->wav);
+	fputc((value >> 24) & 0xff, ww->wav);
+}
+
+static void write_int16(struct wav_writer* ww, int value) {
+	fputc((value >> 0) & 0xff, ww->wav);
+	fputc((value >> 8) & 0xff, ww->wav);
+}
+
+static void write_header(struct wav_writer* ww, int length) {
+	int bytes_per_frame, bytes_per_sec;
+	write_string(ww, "RIFF");
+	write_int32(ww, 4 + 8 + 16 + 8 + length);
+	write_string(ww, "WAVE");
+
+	write_string(ww, "fmt ");
+	write_int32(ww, 16);
+
+	bytes_per_frame = ww->bits_per_sample/8*ww->channels;
+	bytes_per_sec   = bytes_per_frame*ww->sample_rate;
+	write_int16(ww, 1);                   // Format
+	write_int16(ww, ww->channels);        // Channels
+	write_int32(ww, ww->sample_rate);     // Samplerate
+	write_int32(ww, bytes_per_sec);       // Bytes per sec
+	write_int16(ww, bytes_per_frame);     // Bytes per frame
+	write_int16(ww, ww->bits_per_sample); // Bits per sample
+
+	write_string(ww, "data");
+	write_int32(ww, length);
+}
+
+void* wav_write_open(const char *filename, int sample_rate, int bits_per_sample, int channels) {
+	struct wav_writer* ww = (struct wav_writer*) malloc(sizeof(*ww));
+	memset(ww, 0, sizeof(*ww));
+	ww->wav = fopen(filename, "wb");
+	if (ww->wav == NULL) {
+		free(ww);
+		return NULL;
+	}
+	ww->data_length = 0;
+	ww->sample_rate = sample_rate;
+	ww->bits_per_sample = bits_per_sample;
+	ww->channels = channels;
+
+	write_header(ww, ww->data_length);
+	return ww;
+}
+
+void wav_write_close(void* obj) {
+	struct wav_writer* ww = (struct wav_writer*) obj;
+	if (ww->wav == NULL) {
+		free(ww);
+		return;
+	}
+	fseek(ww->wav, 0, SEEK_SET);
+	write_header(ww, ww->data_length);
+	fclose(ww->wav);
+	free(ww);
+}
+
+void wav_write_data(void* obj, const unsigned char* data, int length) {
+	struct wav_writer* ww = (struct wav_writer*) obj;
+	if (ww->wav == NULL)
+		return;
+	fwrite(data, length, 1, ww->wav);
+	ww->data_length += length;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtest/wavwriter.h	Sat Nov 19 22:50:08 2022 +0000
@@ -0,0 +1,36 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 2009 Martin Storsjo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ * -------------------------------------------------------------------
+ */
+
+#ifndef WAVWRITER_H
+#define WAVWRITER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void* wav_write_open(const char *filename, int sample_rate, int bits_per_sample, int channels);
+void wav_write_close(void* obj);
+
+void wav_write_data(void* obj, const unsigned char* data, int length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+