changeset 2290:c4980d89614b

Support WAVE files in media player
author Michael Pavone <pavone@retrodev.com>
date Sat, 04 Feb 2023 23:31:11 -0800
parents 92449b47cce8
children 4de40b13b55f
files mediaplayer.c mediaplayer.h
diffstat 2 files changed, 71 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/mediaplayer.c	Sat Feb 04 22:44:44 2023 -0800
+++ b/mediaplayer.c	Sat Feb 04 23:31:11 2023 -0800
@@ -410,7 +410,35 @@
 
 void wave_frame(media_player *player)
 {
-	render_sleep_ms(15);
+	for (uint32_t remaining_samples = player->wave->sample_rate / 60; remaining_samples > 0; remaining_samples--)
+	{
+		uint32_t sample_size = player->wave->bits_per_sample * player->wave->num_channels / 8;
+		if (sample_size > player->media->size || player->current_offset > player->media->size - sample_size) {
+			player->current_offset = player->wave->format_header.size + offsetof(wave_header, audio_format);
+			player->state = STATE_PAUSED;
+			return;
+		}
+		if (player->wave->bits_per_sample == 16) {
+			int16_t value = read_word_le(player);
+			if (player->wave->num_channels == 1) {
+				render_put_mono_sample(player->audio, value);
+			} else {
+				int16_t right = read_word_le(player);
+				render_put_stereo_sample(player->audio, value, right);
+			}
+		} else {
+			uint8_t sample = read_byte(player);
+			int16_t value = sample * 257 - 128 * 257;
+			if (player->wave->num_channels == 1) {
+				render_put_mono_sample(player->audio, value);
+			} else {
+				sample = read_byte(player);
+				int16_t right = sample * 257 - 128 * 257;
+				render_put_stereo_sample(player->audio, value, right);
+			}
+		}
+
+	}
 }
 
 void flac_frame(media_player *player)
@@ -511,6 +539,38 @@
 	player->current_offset = player->vgm->data_offset + offsetof(vgm_header, data_offset);
 }
 
+static void wave_player_init(media_player *player)
+{
+	player->wave = calloc(1, sizeof(wave_header));
+	memcpy(player->wave, player->media->buffer, offsetof(wave_header, data_header));
+	if (memcmp(player->wave->chunk.format, "WAVE", 4)) {
+		goto format_error;
+	}
+	if (player->wave->chunk.size < offsetof(wave_header, data_header)) {
+		goto format_error;
+	}
+	if (memcmp(player->wave->format_header.id, "fmt ", 4)) {
+		goto format_error;
+	}
+	if (player->wave->format_header.size < offsetof(wave_header, data_header) - offsetof(wave_header, audio_format)) {
+		goto format_error;
+	}
+	if (player->wave->bits_per_sample != 8 && player->wave->bits_per_sample != 16) {
+		goto format_error;
+	}
+	uint32_t data_sub_chunk = player->wave->format_header.size + offsetof(wave_header, audio_format);
+	if (data_sub_chunk > player->media->size || player->media->size - data_sub_chunk < sizeof(riff_sub_chunk)) {
+		goto format_error;
+	}
+	memcpy(&player->wave->data_header, ((uint8_t *)player->media->buffer) + data_sub_chunk, sizeof(riff_sub_chunk));
+	player->current_offset = data_sub_chunk;
+	player->audio = render_audio_source("Audio File", player->wave->sample_rate, 1, player->wave->num_channels);
+	return;
+format_error:
+	player->media_type = MEDIA_UNKNOWN;
+	free(player->wave);
+}
+
 static void resume_player(system_header *system)
 {
 	media_player *player = (media_player *)system;
@@ -589,6 +649,9 @@
 		return AUDIO_VGM;
 	}
 	if (!memcmp(media->buffer, "RIFF", 4)) {
+		if (media->size < sizeof(wave_header)) {
+			return MEDIA_UNKNOWN;
+		}
 		return AUDIO_WAVE;
 	}
 	if (!memcmp(media->buffer, "fLaC", 4)) {
@@ -623,6 +686,9 @@
 	case AUDIO_VGM:
 		vgm_init(player, opts);
 		break;
+	case AUDIO_WAVE:
+		wave_player_init(player);
+		break;
 	}
 
 	return player;
--- a/mediaplayer.h	Sat Feb 04 22:44:44 2023 -0800
+++ b/mediaplayer.h	Sat Feb 04 23:31:11 2023 -0800
@@ -4,6 +4,8 @@
 #include <stdint.h>
 #include "system.h"
 #include "vgm.h"
+#include "wave.h"
+#include "render_audio.h"
 
 typedef struct chip_info chip_info;
 typedef void (*chip_run_fun)(void *context, uint32_t cycle);
@@ -25,6 +27,8 @@
 	vgm_header          *vgm;
 	vgm_extended_header *vgm_ext;
 	data_block          *ym_seek_block;
+	wave_header         *wave;
+	audio_source        *audio;
 	chip_info           *chips;
 	uint32_t            num_chips;
 	uint32_t            current_offset;