wave.cc (3110B)
1 #include "intrinsics.h" 2 #include "memory_arena.h" 3 #include "assets.h" 4 #include "stream.h" 5 #include "log.h" 6 #include "wave.h" 7 8 // TODO: this only works on a little endian machine 9 10 #define WAVEID( a, b, c, d ) ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a 11 12 static const u32 WAVEID_RIFF = WAVEID( 'R', 'I', 'F', 'F' ); 13 static const u32 WAVEID_WAVE = WAVEID( 'W', 'A', 'V', 'E' ); 14 static const u32 WAVEID_fmt = WAVEID( 'f', 'm', 't', ' ' ); 15 static const u32 WAVEID_data = WAVEID( 'd', 'a', 't', 'a' ); 16 17 static const u32 WAVEFORMAT_PCM = 1; 18 19 static bool supported_format( u16 format, u16 num_channels, u16 bits_per_sample ) { 20 if( format != WAVEFORMAT_PCM ) return false; 21 if( num_channels != 1 && num_channels != 2 ) return false; 22 if( bits_per_sample != 16 ) return false; 23 24 return true; 25 } 26 27 bool wave_decode( MemoryArena * arena, u8 * data, size_t data_len, SoundData * sound ) { 28 ReadStream r( data, data_len ); 29 30 // decode wave header 31 u32 id_riff = read_u32( &r ); 32 u32 length = read_u32( &r ); 33 u32 id_wave = read_u32( &r ); 34 35 if( !r.ok ) { 36 WARN( "stream error" ); 37 return false; 38 } 39 if( id_riff != WAVEID_RIFF || id_wave != WAVEID_WAVE ) { 40 WARN( "not a WAVE file" ); 41 return false; 42 } 43 if( length != data_len - 2 * sizeof( u32 ) ) { 44 WARN( "WAVE length and data_len don't match up" ); 45 return false; 46 } 47 48 u32 data_length = 0; 49 50 sound->samples = NULL; 51 52 while( r.ok && !r.done() ) { 53 u32 chunk_id = read_u32( &r ); 54 u32 chunk_length = read_u32( &r ); 55 56 switch( chunk_id ) { 57 case WAVEID_fmt: { 58 if( chunk_length != 16 ) { 59 WARN( "invalid WAVE format chunk" ); 60 return false; 61 } 62 63 u16 format = read_u16( &r ); 64 u16 num_channels = read_u16( &r ); 65 u32 sample_rate = read_u32( &r ); 66 /* u32 data_rate = */ read_u32( &r ); 67 /* u16 block_align = */ read_u16( &r ); 68 u16 bits_per_sample = read_u16( &r ); 69 70 if( !r.ok ) { 71 WARN( "stream error" ); 72 return false; 73 } 74 if( !supported_format( format, num_channels, bits_per_sample ) ) { 75 WARN( "unsupported WAVE format" ); 76 return false; 77 } 78 79 sound->num_channels = num_channels; 80 sound->sample_rate = sample_rate; 81 } break; 82 83 case WAVEID_data: { 84 if( data_length != 0 ) { 85 WARN( "WAVE contains more than one data section" ); 86 return false; 87 } 88 89 sound->samples = r.nocopy< s16 >( chunk_length ); 90 data_length = chunk_length; 91 } break; 92 93 default: { 94 WARN( "unrecognised WAVE chunk: {}", chunk_id ); 95 return false; 96 } 97 } 98 } 99 100 if( sound->samples == NULL ) { 101 WARN( "WAVE contains no data section" ); 102 return false; 103 } 104 105 sound->num_samples = data_length / ( sound->num_channels * sizeof( s16 ) ); 106 107 // uninterleave the samples 108 if( sound->num_channels == 2 ) { 109 MEMARENA_SCOPED_CHECKPOINT( arena ); 110 s16 * scratch = memarena_push_many( arena, s16, sound->num_samples * 2 ); 111 112 for( u32 i = 0; i < sound->num_samples; i++ ) { 113 scratch[ i ] = sound->samples[ i * 2 ]; 114 scratch[ i + sound->num_samples ] = sound->samples[ i * 2 + 1 ]; 115 } 116 117 for( u32 i = 0; i < sound->num_samples * 2; i++ ) { 118 sound->samples[ i ] = scratch[ i ]; 119 } 120 } 121 122 return true; 123 }