Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / playercode / mwav.c
1 /*      MikMod sound library\r
2         (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
3         for complete list.\r
4 \r
5         This library is free software; you can redistribute it and/or modify\r
6         it under the terms of the GNU Library General Public License as\r
7         published by the Free Software Foundation; either version 2 of\r
8         the License, or (at your option) any later version.\r
9  \r
10         This program is distributed in the hope that it will be useful,\r
11         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13         GNU Library General Public License for more details.\r
14  \r
15         You should have received a copy of the GNU Library General Public\r
16         License along with this library; if not, write to the Free Software\r
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
18         02111-1307, USA.\r
19 */\r
20 \r
21 /*==============================================================================\r
22 \r
23   $Id: mwav.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
24 \r
25   WAV sample loader\r
26 \r
27 ==============================================================================*/\r
28 \r
29 /*\r
30    FIXME: Stereo .WAV files are not yet supported as samples.\r
31 */\r
32 \r
33 #ifdef HAVE_CONFIG_H\r
34 #include "config.h"\r
35 #endif\r
36 \r
37 #ifdef HAVE_UNISTD_H\r
38 #include <unistd.h>\r
39 #endif\r
40 \r
41 #include <string.h>\r
42 \r
43 #include "mikmod_internals.h"\r
44 \r
45 #ifdef SUNOS\r
46 extern int fprintf(FILE *, const char *, ...);\r
47 #endif\r
48 \r
49 typedef struct WAV {\r
50         CHAR  rID[4];\r
51         ULONG rLen;\r
52         CHAR  wID[4];\r
53         CHAR  fID[4];\r
54         ULONG fLen;\r
55         UWORD wFormatTag;\r
56         UWORD nChannels;\r
57         ULONG nSamplesPerSec;\r
58         ULONG nAvgBytesPerSec;\r
59         UWORD nBlockAlign;\r
60         UWORD nFormatSpecific;\r
61 } WAV;\r
62 \r
63 SAMPLE* Sample_LoadGeneric_internal(MREADER* reader)\r
64 {\r
65         SAMPLE *si=NULL;\r
66         WAV wh;\r
67         BOOL have_fmt=0;\r
68 \r
69         /* read wav header */\r
70         _mm_read_string(wh.rID,4,reader);\r
71         wh.rLen = _mm_read_I_ULONG(reader);\r
72         _mm_read_string(wh.wID,4,reader);\r
73 \r
74         /* check for correct header */\r
75         if(_mm_eof(reader)|| memcmp(wh.rID,"RIFF",4) || memcmp(wh.wID,"WAVE",4)) {\r
76                 _mm_errno = MMERR_UNKNOWN_WAVE_TYPE;\r
77                 return NULL;\r
78         }\r
79 \r
80         /* scan all RIFF blocks until we find the sample data */\r
81         for(;;) {\r
82                 CHAR dID[4];\r
83                 ULONG len,start;\r
84 \r
85                 _mm_read_string(dID,4,reader);\r
86                 len = _mm_read_I_ULONG(reader);\r
87                 /* truncated file ? */\r
88                 if (_mm_eof(reader)) {\r
89                         _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;\r
90                         return NULL;\r
91                 }\r
92                 start = _mm_ftell(reader);\r
93 \r
94                 /* sample format block\r
95                    should be present only once and before a data block */\r
96                 if(!memcmp(dID,"fmt ",4)) {\r
97                         wh.wFormatTag      = _mm_read_I_UWORD(reader);\r
98                         wh.nChannels       = _mm_read_I_UWORD(reader);\r
99                         wh.nSamplesPerSec  = _mm_read_I_ULONG(reader);\r
100                         wh.nAvgBytesPerSec = _mm_read_I_ULONG(reader);\r
101                         wh.nBlockAlign     = _mm_read_I_UWORD(reader);\r
102                         wh.nFormatSpecific = _mm_read_I_UWORD(reader);\r
103 \r
104 #ifdef MIKMOD_DEBUG\r
105                         fprintf(stderr,"\rwavloader : wFormatTag=%04x blockalign=%04x nFormatSpc=%04x\n",\r
106                                 wh.wFormatTag,wh.nBlockAlign,wh.nFormatSpecific);\r
107 #endif\r
108 \r
109                         if((have_fmt)||(wh.nChannels>1)) {\r
110                                 _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;\r
111                                 return NULL;\r
112                         }\r
113                         have_fmt=1;\r
114                 } else\r
115                 /* sample data block\r
116                    should be present only once and after a format block */\r
117                   if(!memcmp(dID,"data",4)) {\r
118                         if(!have_fmt) {\r
119                                 _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;\r
120                                 return NULL;\r
121                         }\r
122                         if(!(si=(SAMPLE*)_mm_malloc(sizeof(SAMPLE)))) return NULL;\r
123                         si->speed  = wh.nSamplesPerSec/wh.nChannels;\r
124                         si->volume = 64;\r
125                         si->length = len;\r
126                         if(wh.nBlockAlign == 2) {\r
127                                 si->flags    = SF_16BITS | SF_SIGNED;\r
128                                 si->length >>= 1;\r
129                         }\r
130                         si->inflags = si->flags;\r
131                         SL_RegisterSample(si,MD_SNDFX,reader);\r
132                         SL_LoadSamples();\r
133                         \r
134                         /* skip any other remaining blocks - so in case of repeated sample\r
135                            fragments, we'll return the first anyway instead of an error */\r
136                         break;\r
137                 }\r
138                 /* onto next block */\r
139                 _mm_fseek(reader,start+len,SEEK_SET);\r
140                 if (_mm_eof(reader))\r
141                         break;\r
142         }\r
143 \r
144         return si;\r
145 }\r
146 \r
147 MIKMODAPI SAMPLE* Sample_LoadGeneric(MREADER* reader)\r
148 {\r
149         SAMPLE* result;\r
150 \r
151         MUTEX_LOCK(vars);\r
152         result=Sample_LoadGeneric_internal(reader);\r
153         MUTEX_UNLOCK(vars);\r
154 \r
155         return result;\r
156 }\r
157 \r
158 MIKMODAPI SAMPLE* Sample_LoadFP(int fp)\r
159 {\r
160         SAMPLE* result=NULL;\r
161         MREADER* reader;\r
162 \r
163         if((reader=_mm_new_file_reader(fp))) {\r
164                 result=Sample_LoadGeneric(reader);\r
165                 _mm_delete_file_reader(reader);\r
166         }\r
167         return result;\r
168 }\r
169 \r
170 MIKMODAPI SAMPLE* Sample_Load(CHAR* filename)\r
171 {\r
172         int fp;\r
173         SAMPLE *si=NULL;\r
174 \r
175         if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;\r
176         if((fp=_mm_fopen(filename,O_RDONLY))) {\r
177                 si = Sample_LoadFP(fp);\r
178                 _mm_fclose(fp);\r
179         }\r
180         return si;\r
181 }\r
182 \r
183 MIKMODAPI void Sample_Free(SAMPLE* si)\r
184 {\r
185         if(si) {\r
186                 MD_SampleUnload(si->handle);\r
187                 free(si);\r
188         }\r
189 }\r
190 \r
191 void Sample_Free_internal(SAMPLE *si)\r
192 {\r
193         MUTEX_LOCK(vars);\r
194         Sample_Free(si);\r
195         MUTEX_UNLOCK(vars);\r
196 }\r
197 \r
198 /* ex:set ts=4: */\r