Initial revision
[blender.git] / intern / SoundSystem / intern / SND_Utils.cpp
1 /*
2  * SND_Utils.cpp
3  *
4  * Util functions for soundthingies
5  *
6  * $Id$
7  *
8  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version. The Blender
14  * Foundation also sells licenses for use in proprietary software under
15  * the Blender License.  See http://www.blender.org/BL/ for information
16  * about this.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
28  * All rights reserved.
29  *
30  * The Original Code is: all of this file.
31  *
32  * Contributor(s): none yet.
33  *
34  * ***** END GPL/BL DUAL LICENSE BLOCK *****
35  */
36
37 #include "SND_Utils.h"
38 #include "SoundDefines.h"
39 #include "SND_DependKludge.h"
40 /*
41 extern "C" { 
42 #include "license_key.h"
43 }
44 */
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <fcntl.h>
48 #include <math.h>
49 #include <string.h>
50
51 #if defined(WIN32)
52 #include <io.h>
53 #else
54 #include <unistd.h>
55 #endif
56
57 //extern int LICENSE_KEY_VALID;
58 #define LICENSE_KEY_VALID true
59
60 #define BUFFERSIZE 32
61
62 /* loads a file */
63 void* SND_LoadSample(char *filename)
64 {
65         int file, filelen, buffersize = BUFFERSIZE;
66         void* data = NULL;
67
68 #if defined(WIN32)      
69         file = open(filename, O_BINARY|O_RDONLY);
70 #else
71         file = open(filename, 0|O_RDONLY);
72 #endif
73
74         if (file == -1)
75         {
76                 //printf("can't open file.\n");
77                 //printf("press q for quit.\n");
78         }
79         else
80         {
81                 filelen = lseek(file, 0, SEEK_END);
82                 lseek(file, 0, SEEK_SET);
83                 
84                 if (filelen != 0)
85                 {
86                         data = malloc(buffersize);
87
88                         if (read(file, data, buffersize) != buffersize)
89                         {
90                                 free(data);
91                                 data = NULL;
92                         }
93                 }
94                 close(file);
95                 
96         }
97         return (data);
98 }
99
100
101
102 bool SND_IsSampleValid(const STR_String& name, void* memlocation)
103 {
104         bool result = false;
105         bool loadedsample = false;
106         char buffer[BUFFERSIZE];
107         
108         if (!memlocation)
109         {
110                 STR_String samplename = name;
111                 memlocation = SND_LoadSample(samplename.Ptr());
112                 
113                 if (memlocation)
114                         loadedsample = true;
115         }
116         
117         if (memlocation)
118         {
119                 memcpy(&buffer, memlocation, BUFFERSIZE);
120                 
121                 if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8)))
122                 {
123                         int shortbuf = * ((short *) &buffer[20]);
124                         if (shortbuf == SND_WAVE_FORMAT_PCM)
125                                 result = true;
126                         
127                         /* only fmod supports compressed wav */
128 #ifdef USE_FMOD
129                         /* and only valid publishers may use compressed wav */
130                         if (LICENSE_KEY_VALID)
131                         {
132                                 switch (shortbuf)
133                                 {
134                                 case SND_WAVE_FORMAT_ADPCM:
135                                 case SND_WAVE_FORMAT_ALAW:
136                                 case SND_WAVE_FORMAT_MULAW:
137                                 case SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM:
138                                 case SND_WAVE_FORMAT_CONTROL_RES_VQLPC:
139                                 case SND_WAVE_FORMAT_GSM_610:
140                                 case SND_WAVE_FORMAT_MPEG3:
141                                         result = true;
142                                         break;
143                                 default:
144                                         {
145                                                 break;
146                                         }
147                                 }
148                         }
149 #endif
150                 }
151 #ifdef USE_FMOD
152                 /* only valid publishers may use ogg vorbis */
153                 else if (!memcmp(buffer, "OggS", 4) && LICENSE_KEY_VALID)
154                 {
155                         result = true;
156                 }
157                 /* only valid publishers may use mp3 */
158                 else if (((!memcmp(buffer, "ID3", 3)) || (!memcmp(buffer, "ÿû", 2))) && LICENSE_KEY_VALID)
159                 {
160                         result = true;
161                 }
162 #endif
163         }
164         if (loadedsample)
165         {
166                 free(memlocation);
167                 memlocation = NULL;
168         }
169
170         return result;
171 }
172
173
174
175 /* checks if the passed pointer is a valid sample */
176 bool CheckSample(void* sample)
177 {
178         bool valid = false;
179         char buffer[32];
180     
181         memcpy(buffer, sample, 16);
182
183         if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8)))
184         {
185                 valid = true;
186         }
187         
188         return valid;
189 }
190
191
192
193 /* gets the type of the sample (0 == unknown, 1 == PCM etc */
194 unsigned int SND_GetSampleFormat(void* sample)
195 {
196         short sampletype = 0;
197
198         if (CheckSample(sample))
199         {
200                 memcpy(&sampletype, ((char*)sample) + 20, 2);
201         }
202
203         return (unsigned int)sampletype;
204 }
205
206
207
208 /* gets the number of channels in a sample */
209 unsigned int SND_GetNumberOfChannels(void* sample)
210 {
211         short numberofchannels = 0;
212
213         if (CheckSample(sample))
214         {
215                 memcpy(&numberofchannels, ((char*)sample) + 22, 2);
216         }
217
218         return (unsigned int)numberofchannels;
219 }
220
221
222
223 /* gets the samplerate of a sample */
224 unsigned int SND_GetSampleRate(void* sample)
225 {
226         unsigned int samplerate = 0;
227         
228         if (CheckSample(sample))
229         {
230                 memcpy(&samplerate, ((char*)sample) + 24, 4);
231         }
232
233         return samplerate;
234 }
235
236
237
238 /* gets the bitrate of a sample */
239 unsigned int SND_GetBitRate(void* sample)
240 {
241         short bitrate = 0;
242
243         if (CheckSample(sample))
244         {
245                 memcpy(&bitrate, ((char*)sample) + 34, 2);
246         }
247
248         return (unsigned int)bitrate;
249 }
250
251
252
253 /* gets the length of the actual sample data (without the header) */
254 unsigned int SND_GetNumberOfSamples(void* sample)
255 {
256         unsigned int chunklength, length = 0, offset = 16;
257         char data[4];
258         
259         if (CheckSample(sample))
260         {
261                 memcpy(&chunklength, ((char*)sample) + offset, 4);
262                 offset = offset + chunklength + 4;
263                 memcpy(data, ((char*)sample) + offset, 4);
264
265                 // lets find "data"
266                 while (memcmp(data, "data", 4))
267                 {
268                         offset += 4;
269                         memcpy(data, ((char*)sample) + offset, 4);
270                 }
271                 offset += 4;
272                 memcpy(&length, ((char*)sample) + offset, 4);
273         }
274
275         return length;
276 }
277
278
279
280 /* gets the size of the entire header (file - sampledata) */
281 unsigned int SND_GetHeaderSize(void* sample)
282 {
283         unsigned int chunklength, headersize = 0, offset = 16;
284         char data[4];
285         
286         if (CheckSample(sample))
287         {
288                 memcpy(&chunklength, ((char*)sample) + offset, 4);
289                 offset = offset + chunklength + 4;
290                 memcpy(data, ((char*)sample) + offset, 4);
291
292                 // lets find "data"
293                 while (memcmp(data, "data", 4))
294                 {
295                         offset += 4;
296                         memcpy(data, ((char*)sample) + offset, 4);
297                 }
298                 headersize = offset + 8;
299         }
300
301
302         return headersize;
303 }
304
305
306
307 unsigned int SND_GetExtraChunk(void* sample)
308 {
309         unsigned int extrachunk = 0, chunklength, offset = 16;
310         char data[4];
311
312         if (CheckSample(sample))
313         {
314                 memcpy(&chunklength, ((char*)sample) + offset, 4);
315                 offset = offset + chunklength + 4;
316                 memcpy(data, ((char*)sample) + offset, 4);
317
318                 // lets find "cue"
319                 while (memcmp(data, "cue", 3))
320                 {
321                         offset += 4;
322                         memcpy(data, ((char*)sample) + offset, 4);
323                 }
324         }
325
326         return extrachunk;
327 }
328
329
330
331 void SND_GetSampleInfo(signed char* sample, SND_WaveSlot* waveslot)
332 {       
333         WavFileHeader   fileheader;
334         WavFmtHeader    fmtheader;
335         WavFmtExHeader  fmtexheader;
336         WavSampleHeader sampleheader;
337         WavChunkHeader  chunkheader;
338         
339         if (CheckSample(sample))
340         {
341                 memcpy(&fileheader, sample, sizeof(WavFileHeader));
342                 sample += sizeof(WavFileHeader);
343                 fileheader.size = ((fileheader.size+1) & ~1) - 4;
344
345                 while ((fileheader.size != 0) && (memcpy(&chunkheader, sample, sizeof(WavChunkHeader))))
346                 {
347                         sample += sizeof(WavChunkHeader);
348                         if (!memcmp(chunkheader.id, "fmt ", 4))
349                         {
350                                 memcpy(&fmtheader, sample, sizeof(WavFmtHeader));
351                                 waveslot->SetSampleFormat(fmtheader.format);
352
353                                 if (fmtheader.format == 0x0001)
354                                 {
355                                         waveslot->SetNumberOfChannels(fmtheader.numberofchannels);
356                                         waveslot->SetBitRate(fmtheader.bitrate);
357                                         waveslot->SetSampleRate(fmtheader.samplerate);
358                                         sample += chunkheader.size;
359                                 } 
360                                 else
361                                 {
362                                         memcpy(&fmtexheader, sample, sizeof(WavFmtExHeader));
363                                         sample += chunkheader.size;
364                                 }
365                         }
366                         else if (!memcmp(chunkheader.id, "data", 4))
367                         {
368                                 if (fmtheader.format == 0x0001)
369                                 {
370                                         waveslot->SetNumberOfSamples(chunkheader.size);
371                                         sample += chunkheader.size;
372                                 }
373                                 else if (fmtheader.format == 0x0011)
374                                 {
375                                         //IMA ADPCM
376                                 }
377                                 else if (fmtheader.format == 0x0055)
378                                 {
379                                         //MP3 WAVE
380                                 }
381                         }
382                         else if (!memcmp(chunkheader.id, "smpl", 4))
383                         {
384                                 memcpy(&sampleheader, sample, sizeof(WavSampleHeader));
385                                 //loop = sampleheader.loops;
386                                 sample += chunkheader.size;
387                         }
388                         else
389                                 sample += chunkheader.size;
390
391                         sample += chunkheader.size & 1;
392                         fileheader.size -= (((chunkheader.size + 1) & ~1) + 8);
393                 }
394         }
395 }