19 #include "loaders.h" |
19 #include "loaders.h" |
20 |
20 |
21 #ifdef __CPLUSPLUS |
21 #ifdef __CPLUSPLUS |
22 extern "C" { |
22 extern "C" { |
23 #endif |
23 #endif |
24 |
24 |
25 int load_wavpcm (const char *filename, ALenum *format, char ** data, ALsizei *bitsize, ALsizei *freq) { |
25 int load_wavpcm (const char *filename, ALenum *format, char ** data, ALsizei *bitsize, ALsizei *freq) { |
26 WAV_header_t WAVHeader; |
26 WAV_header_t WAVHeader; |
27 FILE *wavfile; |
27 FILE *wavfile; |
28 int32_t t; |
28 int32_t t; |
29 uint32_t n = 0; |
29 uint32_t n = 0; |
30 |
30 |
31 wavfile = Fopen(filename, "rb"); |
31 wavfile = Fopen(filename, "rb"); |
32 |
32 |
33 fread(&WAVHeader.ChunkID, sizeof(uint32_t), 1, wavfile); |
33 fread(&WAVHeader.ChunkID, sizeof(uint32_t), 1, wavfile); |
34 fread(&WAVHeader.ChunkSize, sizeof(uint32_t), 1, wavfile); |
34 fread(&WAVHeader.ChunkSize, sizeof(uint32_t), 1, wavfile); |
35 fread(&WAVHeader.Format, sizeof(uint32_t), 1, wavfile); |
35 fread(&WAVHeader.Format, sizeof(uint32_t), 1, wavfile); |
36 |
36 |
37 #ifdef DEBUG |
37 #ifdef DEBUG |
38 fprintf(stderr, "ChunkID: %X\n", invert_endianness(WAVHeader.ChunkID)); |
38 fprintf(stderr, "ChunkID: %X\n", invert_endianness(WAVHeader.ChunkID)); |
39 fprintf(stderr, "ChunkSize: %d\n", WAVHeader.ChunkSize); |
39 fprintf(stderr, "ChunkSize: %d\n", WAVHeader.ChunkSize); |
40 fprintf(stderr, "Format: %X\n", invert_endianness(WAVHeader.Format)); |
40 fprintf(stderr, "Format: %X\n", invert_endianness(WAVHeader.Format)); |
41 #endif |
41 #endif |
42 |
42 |
43 fread(&WAVHeader.Subchunk1ID, sizeof(uint32_t), 1, wavfile); |
43 fread(&WAVHeader.Subchunk1ID, sizeof(uint32_t), 1, wavfile); |
44 fread(&WAVHeader.Subchunk1Size, sizeof(uint32_t), 1, wavfile); |
44 fread(&WAVHeader.Subchunk1Size, sizeof(uint32_t), 1, wavfile); |
45 fread(&WAVHeader.AudioFormat, sizeof(uint16_t), 1, wavfile); |
45 fread(&WAVHeader.AudioFormat, sizeof(uint16_t), 1, wavfile); |
46 fread(&WAVHeader.NumChannels, sizeof(uint16_t), 1, wavfile); |
46 fread(&WAVHeader.NumChannels, sizeof(uint16_t), 1, wavfile); |
47 fread(&WAVHeader.SampleRate, sizeof(uint32_t), 1, wavfile); |
47 fread(&WAVHeader.SampleRate, sizeof(uint32_t), 1, wavfile); |
48 fread(&WAVHeader.ByteRate, sizeof(uint32_t), 1, wavfile); |
48 fread(&WAVHeader.ByteRate, sizeof(uint32_t), 1, wavfile); |
49 fread(&WAVHeader.BlockAlign, sizeof(uint16_t), 1, wavfile); |
49 fread(&WAVHeader.BlockAlign, sizeof(uint16_t), 1, wavfile); |
50 fread(&WAVHeader.BitsPerSample, sizeof(uint16_t), 1, wavfile); |
50 fread(&WAVHeader.BitsPerSample, sizeof(uint16_t), 1, wavfile); |
51 |
51 |
52 #ifdef DEBUG |
52 #ifdef DEBUG |
53 fprintf(stderr, "Subchunk1ID: %X\n", invert_endianness(WAVHeader.Subchunk1ID)); |
53 fprintf(stderr, "Subchunk1ID: %X\n", invert_endianness(WAVHeader.Subchunk1ID)); |
54 fprintf(stderr, "Subchunk1Size: %d\n", WAVHeader.Subchunk1Size); |
54 fprintf(stderr, "Subchunk1Size: %d\n", WAVHeader.Subchunk1Size); |
55 fprintf(stderr, "AudioFormat: %d\n", WAVHeader.AudioFormat); |
55 fprintf(stderr, "AudioFormat: %d\n", WAVHeader.AudioFormat); |
56 fprintf(stderr, "NumChannels: %d\n", WAVHeader.NumChannels); |
56 fprintf(stderr, "NumChannels: %d\n", WAVHeader.NumChannels); |
57 fprintf(stderr, "SampleRate: %d\n", WAVHeader.SampleRate); |
57 fprintf(stderr, "SampleRate: %d\n", WAVHeader.SampleRate); |
58 fprintf(stderr, "ByteRate: %d\n", WAVHeader.ByteRate); |
58 fprintf(stderr, "ByteRate: %d\n", WAVHeader.ByteRate); |
59 fprintf(stderr, "BlockAlign: %d\n", WAVHeader.BlockAlign); |
59 fprintf(stderr, "BlockAlign: %d\n", WAVHeader.BlockAlign); |
60 fprintf(stderr, "BitsPerSample: %d\n", WAVHeader.BitsPerSample); |
60 fprintf(stderr, "BitsPerSample: %d\n", WAVHeader.BitsPerSample); |
61 #endif |
61 #endif |
62 |
62 |
63 do { /*remove useless header chunks (plenty room for improvements)*/ |
63 do { /*remove useless header chunks (plenty room for improvements)*/ |
64 t = fread(&WAVHeader.Subchunk2ID, sizeof(uint32_t), 1, wavfile); |
64 t = fread(&WAVHeader.Subchunk2ID, sizeof(uint32_t), 1, wavfile); |
65 if (invert_endianness(WAVHeader.Subchunk2ID) == 0x64617461) |
65 if (invert_endianness(WAVHeader.Subchunk2ID) == 0x64617461) |
66 break; |
66 break; |
67 if (t <= 0) { /*eof*/ |
67 if (t <= 0) { /*eof*/ |
68 fprintf(stderr, "ERROR: wrong WAV header\n"); |
68 fprintf(stderr, "ERROR: wrong WAV header\n"); |
69 return AL_FALSE; |
69 return AL_FALSE; |
70 } |
70 } |
71 } while (1); |
71 } while (1); |
72 fread(&WAVHeader.Subchunk2Size, sizeof(uint32_t), 1, wavfile); |
72 fread(&WAVHeader.Subchunk2Size, sizeof(uint32_t), 1, wavfile); |
73 |
73 |
74 #ifdef DEBUG |
74 #ifdef DEBUG |
75 fprintf(stderr, "Subchunk2ID: %X\n", invert_endianness(WAVHeader.Subchunk2ID)); |
75 fprintf(stderr, "Subchunk2ID: %X\n", invert_endianness(WAVHeader.Subchunk2ID)); |
76 fprintf(stderr, "Subchunk2Size: %d\n", WAVHeader.Subchunk2Size); |
76 fprintf(stderr, "Subchunk2Size: %d\n", WAVHeader.Subchunk2Size); |
77 #endif |
77 #endif |
78 |
78 |
79 *data = (char*) Malloc (sizeof(char) * WAVHeader.Subchunk2Size); |
79 *data = (char*) Malloc (sizeof(char) * WAVHeader.Subchunk2Size); |
80 |
80 |
81 /*this could be improved*/ |
81 /*this could be improved*/ |
82 do { |
82 do { |
83 n += fread(&((*data)[n]), sizeof(uint8_t), 1, wavfile); |
83 n += fread(&((*data)[n]), sizeof(uint8_t), 1, wavfile); |
84 } while (n < WAVHeader.Subchunk2Size); |
84 } while (n < WAVHeader.Subchunk2Size); |
85 |
85 |
86 fclose(wavfile); |
86 fclose(wavfile); |
87 |
87 |
88 #ifdef DEBUG |
88 #ifdef DEBUG |
89 fprintf(stderr, "Last two bytes of data: %X%X\n", (*data)[n-2], (*data)[n-1]); |
89 fprintf(stderr, "Last two bytes of data: %X%X\n", (*data)[n-2], (*data)[n-1]); |
90 #endif |
90 #endif |
91 |
91 |
92 /*remaining parameters*/ |
92 /*remaining parameters*/ |
93 /*Valid formats are AL_FORMAT_MONO8, AL_FORMAT_MONO16, AL_FORMAT_STEREO8, and AL_FORMAT_STEREO16*/ |
93 /*Valid formats are AL_FORMAT_MONO8, AL_FORMAT_MONO16, AL_FORMAT_STEREO8, and AL_FORMAT_STEREO16*/ |
94 if (WAVHeader.NumChannels == 1) { |
94 if (WAVHeader.NumChannels == 1) { |
95 if (WAVHeader.BitsPerSample == 8) |
95 if (WAVHeader.BitsPerSample == 8) |
96 *format = AL_FORMAT_MONO8; |
96 *format = AL_FORMAT_MONO8; |
97 else { |
97 else { |
98 if (WAVHeader.BitsPerSample == 16) |
98 if (WAVHeader.BitsPerSample == 16) |
99 *format = AL_FORMAT_MONO16; |
99 *format = AL_FORMAT_MONO16; |
100 else { |
100 else { |
101 fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n"); |
101 fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n"); |
102 return AL_FALSE; |
102 return AL_FALSE; |
103 } |
103 } |
104 } |
104 } |
105 } else { |
105 } else { |
106 if (WAVHeader.NumChannels == 2) { |
106 if (WAVHeader.NumChannels == 2) { |
107 if (WAVHeader.BitsPerSample == 8) |
107 if (WAVHeader.BitsPerSample == 8) |
108 *format = AL_FORMAT_STEREO8; |
108 *format = AL_FORMAT_STEREO8; |
109 else { |
109 else { |
110 if (WAVHeader.BitsPerSample == 16) |
110 if (WAVHeader.BitsPerSample == 16) |
111 *format = AL_FORMAT_STEREO16; |
111 *format = AL_FORMAT_STEREO16; |
112 else { |
112 else { |
113 fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n"); |
113 fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n"); |
114 return AL_FALSE; |
114 return AL_FALSE; |
115 } |
115 } |
116 } |
116 } |
117 } else { |
117 } else { |
118 fprintf(stderr, "ERROR: wrong WAV header - format value\n"); |
118 fprintf(stderr, "ERROR: wrong WAV header - format value\n"); |
119 return AL_FALSE; |
119 return AL_FALSE; |
120 } |
120 } |
121 } |
121 } |
122 |
122 |
123 *bitsize = WAVHeader.Subchunk2Size; |
123 *bitsize = WAVHeader.Subchunk2Size; |
124 *freq = WAVHeader.SampleRate; |
124 *freq = WAVHeader.SampleRate; |
125 return AL_TRUE; |
125 return AL_TRUE; |
126 } |
126 } |
127 |
127 |
128 |
128 |
129 int load_oggvorbis (const char *filename, ALenum *format, char **data, ALsizei *bitsize, ALsizei *freq) { |
129 int load_oggvorbis (const char *filename, ALenum *format, char **data, ALsizei *bitsize, ALsizei *freq) { |
130 /*implementation inspired from http://www.devmaster.net/forums/showthread.php?t=1153 */ |
130 /*implementation inspired from http://www.devmaster.net/forums/showthread.php?t=1153 */ |
131 FILE *oggFile; /*ogg handle*/ |
131 FILE *oggFile; /*ogg handle*/ |
132 OggVorbis_File oggStream; /*stream handle*/ |
132 OggVorbis_File oggStream; /*stream handle*/ |
133 vorbis_info *vorbisInfo; /*some formatting data*/ |
133 vorbis_info *vorbisInfo; /*some formatting data*/ |
134 int64_t pcm_length; /*length of the decoded data*/ |
134 int64_t pcm_length; /*length of the decoded data*/ |
135 int size = 0; |
135 int size = 0; |
136 int section, result; |
136 int section, result; |
137 #ifdef DEBUG |
137 #ifdef DEBUG |
138 int i; |
138 int i; |
139 vorbis_comment *vorbisComment; /*other less useful data*/ |
139 vorbis_comment *vorbisComment; /*other less useful data*/ |
140 #endif |
140 #endif |
141 |
141 |
142 oggFile = Fopen(filename, "rb"); |
142 oggFile = Fopen(filename, "rb"); |
143 result = ov_open(oggFile, &oggStream, NULL, 0); /*TODO: check returning value of result*/ |
143 result = ov_open(oggFile, &oggStream, NULL, 0); /*TODO: check returning value of result*/ |
144 fclose(oggFile); |
144 fclose(oggFile); |
145 |
145 |
146 vorbisInfo = ov_info(&oggStream, -1); |
146 vorbisInfo = ov_info(&oggStream, -1); |
147 pcm_length = ov_pcm_total(&oggStream, -1) << vorbisInfo->channels; |
147 pcm_length = ov_pcm_total(&oggStream, -1) << vorbisInfo->channels; |
148 |
148 |
149 #ifdef DEBUG |
149 #ifdef DEBUG |
150 vorbisComment = ov_comment(&oggStream, -1); |
150 vorbisComment = ov_comment(&oggStream, -1); |
151 fprintf(stderr, "Version: %d\n", vorbisInfo->version); |
151 fprintf(stderr, "Version: %d\n", vorbisInfo->version); |
152 fprintf(stderr, "Channels: %d\n", vorbisInfo->channels); |
152 fprintf(stderr, "Channels: %d\n", vorbisInfo->channels); |
153 fprintf(stderr, "Rate (Hz): %ld\n", vorbisInfo->rate); |
153 fprintf(stderr, "Rate (Hz): %ld\n", vorbisInfo->rate); |
154 fprintf(stderr, "Bitrate Upper: %ld\n", vorbisInfo->bitrate_upper); |
154 fprintf(stderr, "Bitrate Upper: %ld\n", vorbisInfo->bitrate_upper); |
155 fprintf(stderr, "Bitrate Nominal: %ld\n", vorbisInfo->bitrate_nominal); |
155 fprintf(stderr, "Bitrate Nominal: %ld\n", vorbisInfo->bitrate_nominal); |
156 fprintf(stderr, "Bitrate Lower: %ld\n", vorbisInfo->bitrate_lower); |
156 fprintf(stderr, "Bitrate Lower: %ld\n", vorbisInfo->bitrate_lower); |
157 fprintf(stderr, "Bitrate Windows: %ld\n", vorbisInfo->bitrate_window); |
157 fprintf(stderr, "Bitrate Windows: %ld\n", vorbisInfo->bitrate_window); |
158 fprintf(stderr, "Vendor: %s\n", vorbisComment->vendor); |
158 fprintf(stderr, "Vendor: %s\n", vorbisComment->vendor); |
159 fprintf(stderr, "PCM data size: %lld\n", pcm_length); |
159 fprintf(stderr, "PCM data size: %lld\n", pcm_length); |
160 fprintf(stderr, "# comment: %d\n", vorbisComment->comments); |
160 fprintf(stderr, "# comment: %d\n", vorbisComment->comments); |
161 for (i = 0; i < vorbisComment->comments; i++) |
161 for (i = 0; i < vorbisComment->comments; i++) |
162 fprintf(stderr, "\tComment %d: %s\n", i, vorbisComment->user_comments[i]); |
162 fprintf(stderr, "\tComment %d: %s\n", i, vorbisComment->user_comments[i]); |
163 #endif |
163 #endif |
164 |
164 |
165 /*allocates enough room for the decoded data*/ |
165 /*allocates enough room for the decoded data*/ |
166 *data = (char*) Malloc (sizeof(char) * pcm_length); |
166 *data = (char*) Malloc (sizeof(char) * pcm_length); |
167 |
167 |
168 /*there *should* not be ogg at 8 bits*/ |
168 /*there *should* not be ogg at 8 bits*/ |
169 if (vorbisInfo->channels == 1) |
169 if (vorbisInfo->channels == 1) |
170 *format = AL_FORMAT_MONO16; |
170 *format = AL_FORMAT_MONO16; |
171 else { |
171 else { |
172 if (vorbisInfo->channels == 2) |
172 if (vorbisInfo->channels == 2) |
173 *format = AL_FORMAT_STEREO16; |
173 *format = AL_FORMAT_STEREO16; |
174 else { |
174 else { |
175 fprintf(stderr, "ERROR: wrong OGG header - channel value (%d)\n", vorbisInfo->channels); |
175 fprintf(stderr, "ERROR: wrong OGG header - channel value (%d)\n", vorbisInfo->channels); |
176 return AL_FALSE; |
176 return AL_FALSE; |
177 } |
177 } |
178 } |
178 } |
179 |
179 |
180 while(size < pcm_length) { |
180 while(size < pcm_length) { |
181 /*ov_read decodes the ogg stream and storse the pcm in data*/ |
181 /*ov_read decodes the ogg stream and storse the pcm in data*/ |
182 result = ov_read (&oggStream, *data + size, pcm_length - size, 0, 2, 1, §ion); |
182 result = ov_read (&oggStream, *data + size, pcm_length - size, 0, 2, 1, §ion); |
183 if(result > 0) { |
183 if(result > 0) { |
184 size += result; |
184 size += result; |
185 } else { |
185 } else { |
186 if (result == 0) |
186 if (result == 0) |
187 break; |
187 break; |
188 else { |
188 else { |
189 fprintf(stderr, "ERROR: end of file from OGG stream\n"); |
189 fprintf(stderr, "ERROR: end of file from OGG stream\n"); |
190 return AL_FALSE; |
190 return AL_FALSE; |
191 } |
191 } |
192 } |
192 } |
193 } |
193 } |
194 |
194 |
195 /*records the last fields*/ |
195 /*records the last fields*/ |
196 *bitsize = size; |
196 *bitsize = size; |
197 *freq = vorbisInfo->rate; |
197 *freq = vorbisInfo->rate; |
198 |
198 |
199 ov_clear (&oggStream); |
199 ov_clear (&oggStream); |
200 return AL_TRUE; |
200 return AL_TRUE; |
201 } |
201 } |
202 |
202 |
203 #ifdef __CPLUSPLUS |
203 #ifdef __CPLUSPLUS |
204 } |
204 } |
205 #endif |
205 #endif |