medfall

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 8724d6d2f2b8e32fc9b9baf767c1e231cda91994
parent 771d40488392a6cb1b755a45fe664bd992bb7ad0
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sat Oct 31 23:24:41 +0000

Add WAV decoder

Diffstat:
intrinsics.h | 11++++++++---
wave.cc | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
wave.h | 16++++++++++++++++
3 files changed, 127 insertions(+), 3 deletions(-)
diff --git a/intrinsics.h b/intrinsics.h @@ -23,6 +23,7 @@ typedef double f64; #define is_power_of_2( n ) ( ( ( n ) & ( ( n ) - 1 ) ) == 0 ) #define align_power_of_2( n, alignment ) ( ( ( n ) + ( alignment ) - 1 ) & ~( ( alignment ) - 1 ) ) +#define align2( n ) align_power_of_2( n, 4 ) #define align4( n ) align_power_of_2( n, 4 ) #define align8( n ) align_power_of_2( n, 8 ) #define align16( n ) align_power_of_2( n, 16 ) @@ -30,18 +31,22 @@ typedef double f64; // TODO: clashes with some crap in std::string #define align_TODO( n, alignment ) ( ( ( n ) + ( alignment ) - 1 ) / ( alignment ) * ( alignment ) ) -inline size_t kilobytes( const size_t kb ) { +inline constexpr size_t kilobytes( const size_t kb ) { return kb * 1024; } -inline size_t megabytes( const size_t mb ) { +inline constexpr size_t megabytes( const size_t mb ) { return kilobytes( mb ) * 1024; } -inline size_t gigabytes( const size_t gb ) { +inline constexpr size_t gigabytes( const size_t gb ) { return megabytes( gb ) * 1024; } +inline u32 min_u32( u32 a, u32 b ) { + return a < b ? a : b; +} + inline u32 max_u32( u32 a, u32 b ) { return a > b ? a : b; } diff --git a/wave.cc b/wave.cc @@ -0,0 +1,103 @@ +#include "intrinsics.h" +#include "memory_arena.h" +#include "wave.h" + +// TODO: this only works on a little endian machine + +#define WAVEID( a, b, c, d ) ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a + +enum WaveID { + WAVEID_RIFF = WAVEID( 'R', 'I', 'F', 'F' ), + WAVEID_WAVE = WAVEID( 'W', 'A', 'V', 'E' ), + WAVEID_fmt = WAVEID( 'f', 'm', 't', ' ' ), + WAVEID_data = WAVEID( 'd', 'a', 't', 'a' ), +}; + +struct WaveHeader { + u32 id_riff; + u32 length; + u32 id_wave; +}; + +struct WaveChunk { + u32 id; + u32 length; +}; + +struct WaveFMT { + u32 id; + u32 length; + + u16 format; + u16 num_channels; + u32 sample_rate; + u32 data_rate; + u16 block_align; + u16 bits_per_sample; +}; + +bool wave_decode( MemoryArena * arena, u8 * data, Sound * sound ) { + WaveHeader * header = ( WaveHeader * ) data; + + if( header->id_riff != WAVEID_RIFF || header->id_wave != WAVEID_WAVE ) { + printf( "bad header\n" ); + return false; + } + + u32 pos = sizeof( WaveHeader ); + u32 data_length; + + while( pos < header->length ) { + WaveChunk * chunk = ( WaveChunk * ) ( data + pos ); + + switch( chunk->id ) { + case WAVEID_fmt: { + if( chunk->length != 16 ) return false; + + WaveFMT * fmt = ( WaveFMT * ) chunk; + + if( ( fmt->num_channels != 1 && fmt->num_channels != 2 ) || fmt->bits_per_sample != 16 ) { + return false; + } + + sound->num_channels = fmt->num_channels; + sound->sample_rate = fmt->sample_rate; + + break; + } + + case WAVEID_data: { + sound->samples = ( s16 * ) ( chunk + 1 ); + data_length = chunk->length; + break; + }; + + default: { + printf( "wtf is this\n" ); + return false; + } + } + + pos += sizeof( WaveChunk ) + align2( chunk->length ); + } + + sound->num_samples = data_length / ( sound->num_channels * sizeof( s16 ) ); + + // uninterleave the samples + if( sound->num_channels == 2 ) { + MEMARENA_SCOPED_CHECKPOINT( arena ); + printf( "%u\n", sound->num_samples * 2 ); + s16 * scratch = memarena_push_many( arena, s16, sound->num_samples * 2 ); + + for( u32 i = 0; i < sound->num_samples; i++ ) { + scratch[ i ] = sound->samples[ i * 2 ]; + scratch[ i + sound->num_samples ] = sound->samples[ i * 2 + 1 ]; + } + + for( u32 i = 0; i < sound->num_samples * 2; i++ ) { + sound->samples[ i ] = scratch[ i ]; + } + } + + return true; +} diff --git a/wave.h b/wave.h @@ -0,0 +1,16 @@ +#ifndef _WAVE_H_ +#define _WAVE_H_ + +#include "memory_arena.h" + +struct Sound { + u32 num_samples; + u32 sample_rate; + u32 num_channels; + + s16 * samples; +}; + +bool wave_decode( MemoryArena * arena, u8 * data, Sound * sound ); + +#endif // _WAVE_H_