dropped aas, moved to maxmod
[gbajam21] / tools / mmutil / wav.c
1 /****************************************************************************
2  *                                                          __              *
3  *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
4  *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
5  *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
6  *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
7  *                                                                          *
8  *         Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org)         *
9  *                                                                          *
10  * Permission to use, copy, modify, and/or distribute this software for any *
11  * purpose with or without fee is hereby granted, provided that the above   *
12  * copyright notice and this permission notice appear in all copies.        *
13  *                                                                          *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         *
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  *
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   *
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    *
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *
20  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           *
21  ****************************************************************************/
22
23 // WAV file loader
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include "defs.h"
28 #include "files.h"
29 #include "mas.h"
30 #include "wav.h"
31 #include "simple.h"
32 #include "samplefix.h"
33
34 int Load_WAV( Sample* samp, bool verbose, bool fix )
35 {
36         unsigned int file_size;
37         unsigned int bit_depth = 8;
38         unsigned int hasformat = 0;
39         unsigned int hasdata = 0;
40         unsigned int chunk_code;
41         unsigned int chunk_size;
42         unsigned int num_channels = 0;
43         
44         if( verbose )
45                 printf( "Loading WAV file...\n" );
46         
47         // initialize data
48         memset( samp, 0, sizeof( Sample ) );
49         
50         file_size = file_tell_size();
51         
52         read32();                                               // "RIFF"
53         read32();                                               // filesize-8
54         read32();                                               // "WAVE"
55         
56         while( 1 )
57         {
58                 // break on end of file
59                 if( file_tell_read() >= file_size ) break;
60                 
61                 // read chunk code and length
62                 chunk_code = read32();
63                 chunk_size = read32();
64                 
65                 // parse chunk code
66                 switch( chunk_code )
67                 {
68                 //---------------------------------------------------------------------
69                 case ' tmf':    // format chunk
70                 //---------------------------------------------------------------------
71                         
72                         // check compression code (1 = PCM)
73                         if( read16() != 1 )
74                         {
75                                 if( verbose )
76                                         printf( "Unsupported WAV format.\n" );
77                                 return LOADWAV_UNKNOWN_COMP;
78                         }
79                         
80                         // read # of channels
81                         num_channels = read16();
82                         
83                         // read sampling frequency
84                         samp->frequency = read32();
85                         
86                         // skip average something, wBlockAlign
87                         read32();
88                         read16();
89                         
90                         // get bit depth, catch unsupported values
91                         bit_depth = read16();
92                         if( bit_depth != 8 && bit_depth != 16 )
93                         {
94                                 if( verbose )
95                                         printf( "Unsupported bit-depth.\n" );
96                                 return LOADWAV_UNSUPPORTED_BD;
97                         }
98                         
99                         if( bit_depth == 16 )
100                                 samp->format |= SAMPF_16BIT;
101                         
102                         // print verbose data
103                         if( verbose )
104                         {
105                                 printf( "Sample Rate...%i\n", samp->frequency );
106                                 printf( "Bit Depth.....%i-bit\n", bit_depth );
107                         }
108                         
109                         // skip the rest of the chunk (if any)
110                         if( (chunk_size - 0x10) > 0 )
111                                 skip8( (chunk_size - 0x10) );
112                         
113                         hasformat = 1;
114                         break;
115                         
116                 //---------------------------------------------------------------------
117                 case 'atad':    // data chunk
118                 //---------------------------------------------------------------------
119                 {
120                         int t, c, dat;
121                         
122                         if( !hasformat )
123                         {
124                                 return LOADWAV_CORRUPT;
125                         }
126                         
127                         if( verbose )
128                                 printf( "Loading Sample Data...\n" );
129                         
130                         // clip chunk size against end of file (for some borked wavs...)
131                         {
132                                 int br = file_size - file_tell_read();
133                                 chunk_size = chunk_size > br ? br : chunk_size;
134                         }
135                         
136                         samp->sample_length = chunk_size / (bit_depth/8) / num_channels;
137                         samp->data = malloc( chunk_size );
138                         
139                         // read sample data
140                         for( t = 0; t < samp->sample_length; t++ )
141                         {
142                                 dat = 0;
143                                 
144                                 // for multi-channel samples, get average value
145                                 for( c = 0; c < num_channels; c++ )
146                                 {
147                                         dat += bit_depth == 8 ? ((int)read8()) - 128 : ((short)read16());
148                                 }
149                                 dat /= num_channels;
150                                 
151                                 if( bit_depth == 8 )
152                                 {
153                                         ((u8*)samp->data)[t] = dat + 128;
154                                 }
155                                 else
156                                 {
157                                         ((u16*)samp->data)[t] = dat + 32768;
158                                 }
159                         }
160                         
161                         hasdata = 1;
162                         
163                         break;
164                 }
165                 //------------------------------------------------------------------------------
166                 case 'lpms':    // sampler chunk
167                 //------------------------------------------------------------------------------
168                 {
169                         int pos;
170                         skip8(  4               // manufacturer
171                                         +4              // product
172                                         +4              // sample period
173                                         +4              // midi unity note
174                                         +4              // midi pitch fraction
175                                         +4              // smpte format
176                                         +4              // smpte offset
177                                         );
178                         int num_sample_loops = read32();
179                         
180                         read32();               // sample data
181                         
182                         pos = 36;
183                         
184                         // check for sample looping data
185                         if( num_sample_loops )
186                         {
187                                 read32();       // cue point ID
188                                 int loop_type = read32();
189                                 pos += 8;
190                                 
191                                 if( loop_type < 2 )
192                                 {
193                                         // sample    | internal
194                                         // 0=forward | 1
195                                         // 1=bidi    | 2
196                                         samp->loop_type = loop_type + 1;
197                                         samp->loop_start = read32();
198                                         samp->loop_end = read32();
199                                         
200                                         // clip loop start against sample length
201                                         if( samp->loop_end > samp->sample_length ) {
202                                                 samp->loop_end = samp->sample_length;
203                                         }
204                                         
205                                         // disable tiny loop
206                                         // catch invalid loop
207                                         if( (samp->loop_start > samp->sample_length) ||
208                                                 (samp->loop_end - samp->loop_start < 16) ) {
209                                                 
210                                                 samp->loop_type = 0;
211                                                 samp->loop_start = 0;
212                                                 samp->loop_end = 0;
213                                         }
214                                         
215                                         // ignore fractional
216                                         // ignore play count
217                                         pos += 8;
218                                 }
219                         }
220                         
221                         skip8( chunk_size - pos );
222                         break;
223                 }       
224                 default:
225                         skip8( chunk_size );
226                 }
227         }
228         
229         if( hasformat && hasdata )
230         {
231                 if( fix ) FixSample( samp );
232                 return LOADWAV_OK;
233         }
234         else
235         {
236                 return LOADWAV_CORRUPT;
237         }
238 }