|
1 /* |
|
2 * OpenAL Bridge - a simple portable library for OpenAL interface |
|
3 * Copyright (c) 2009 Vittorio Giovara <vittorio.giovara@gmail.com> |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation; version 2 of the License |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
|
17 */ |
|
18 |
|
19 #include <stdio.h> |
|
20 #include <stdlib.h> |
|
21 #include <stdint.h> |
|
22 #include "al.h" |
|
23 #include "alc.h" |
|
24 #include "loaders.h" |
|
25 #include "endianness.h" |
|
26 #include "wrappers.h" |
|
27 |
|
28 #ifdef __CPLUSPLUS |
|
29 extern "C" { |
|
30 #endif |
|
31 |
|
32 extern int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes); |
|
33 extern long ov_read(OggVorbis_File *vf,char *buffer,int length,int bigendianp,int word,int sgned,int *bitstream); |
|
34 extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); |
|
35 extern long ov_read(OggVorbis_File *vf,char *buffer,int length,int bigendianp,int word,int sgned,int *bitstream); |
|
36 extern vorbis_info *ov_info(OggVorbis_File *vf,int link); |
|
37 extern vorbis_comment *ov_comment(OggVorbis_File *f, int num); |
|
38 |
|
39 int load_WavPcm (const char *filename, ALenum *format, uint8_t** data, ALsizei *bitsize, ALsizei *freq) { |
|
40 WAV_header_t WAVHeader; |
|
41 FILE *wavfile; |
|
42 int t, n = 0; |
|
43 |
|
44 wavfile = Fopen(filename, "rb"); |
|
45 |
|
46 fread(&WAVHeader.ChunkID, sizeof(uint32_t), 1, wavfile); |
|
47 fread(&WAVHeader.ChunkSize, sizeof(uint32_t), 1, wavfile); |
|
48 fread(&WAVHeader.Format, sizeof(uint32_t), 1, wavfile); |
|
49 |
|
50 #ifdef DEBUG |
|
51 fprintf(stderr, "ChunkID: %X\n", invert_endianness(WAVHeader.ChunkID)); |
|
52 fprintf(stderr, "ChunkSize: %d\n", WAVHeader.ChunkSize); |
|
53 fprintf(stderr, "Format: %X\n", invert_endianness(WAVHeader.Format)); |
|
54 #endif |
|
55 |
|
56 fread(&WAVHeader.Subchunk1ID, sizeof(uint32_t), 1, wavfile); |
|
57 fread(&WAVHeader.Subchunk1Size, sizeof(uint32_t), 1, wavfile); |
|
58 fread(&WAVHeader.AudioFormat, sizeof(uint16_t), 1, wavfile); |
|
59 fread(&WAVHeader.NumChannels, sizeof(uint16_t), 1, wavfile); |
|
60 fread(&WAVHeader.SampleRate, sizeof(uint32_t), 1, wavfile); |
|
61 fread(&WAVHeader.ByteRate, sizeof(uint32_t), 1, wavfile); |
|
62 fread(&WAVHeader.BlockAlign, sizeof(uint16_t), 1, wavfile); |
|
63 fread(&WAVHeader.BitsPerSample, sizeof(uint16_t), 1, wavfile); |
|
64 |
|
65 #ifdef DEBUG |
|
66 fprintf(stderr, "Subchunk1ID: %X\n", invert_endianness(WAVHeader.Subchunk1ID)); |
|
67 fprintf(stderr, "Subchunk1Size: %d\n", WAVHeader.Subchunk1Size); |
|
68 fprintf(stderr, "AudioFormat: %d\n", WAVHeader.AudioFormat); |
|
69 fprintf(stderr, "NumChannels: %d\n", WAVHeader.NumChannels); |
|
70 fprintf(stderr, "SampleRate: %d\n", WAVHeader.SampleRate); |
|
71 fprintf(stderr, "ByteRate: %d\n", WAVHeader.ByteRate); |
|
72 fprintf(stderr, "BlockAlign: %d\n", WAVHeader.BlockAlign); |
|
73 fprintf(stderr, "BitsPerSample: %d\n", WAVHeader.BitsPerSample); |
|
74 #endif |
|
75 |
|
76 do { //remove useless header chunks (plenty room for improvements) |
|
77 t = fread(&WAVHeader.Subchunk2ID, sizeof(uint32_t), 1, wavfile); |
|
78 if (invert_endianness(WAVHeader.Subchunk2ID) == 0x64617461) |
|
79 break; |
|
80 if (t <= 0) { //eof found |
|
81 fprintf(stderr, "ERROR: wrong WAV header\n"); |
|
82 return AL_FALSE; |
|
83 } |
|
84 } while (1); |
|
85 fread(&WAVHeader.Subchunk2Size, sizeof(uint32_t), 1, wavfile); |
|
86 |
|
87 #ifdef DEBUG |
|
88 fprintf(stderr, "Subchunk2ID: %X\n", invert_endianness(WAVHeader.Subchunk2ID)); |
|
89 fprintf(stderr, "Subchunk2Size: %d\n", WAVHeader.Subchunk2Size); |
|
90 #endif |
|
91 |
|
92 *data = (uint8_t*) malloc (sizeof(uint8_t) * WAVHeader.Subchunk2Size); |
|
93 |
|
94 //this could be improved |
|
95 do { |
|
96 n += fread(&((*data)[n]), sizeof(uint8_t), 1, wavfile); |
|
97 } while (n < WAVHeader.Subchunk2Size); |
|
98 |
|
99 fclose(wavfile); |
|
100 |
|
101 #ifdef DEBUG |
|
102 fprintf(stderr, "Last two bytes of data: %X%X\n", (*data)[n-2], (*data)[n-1]); |
|
103 #endif |
|
104 |
|
105 /*remaining parameters*/ |
|
106 //Valid formats are AL_FORMAT_MONO8, AL_FORMAT_MONO16, AL_FORMAT_STEREO8, and AL_FORMAT_STEREO16. |
|
107 if (WAVHeader.NumChannels == 1) { |
|
108 if (WAVHeader.BitsPerSample == 8) |
|
109 *format = AL_FORMAT_MONO8; |
|
110 else { |
|
111 if (WAVHeader.BitsPerSample == 16) |
|
112 *format = AL_FORMAT_MONO16; |
|
113 else { |
|
114 fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n"); |
|
115 return AL_FALSE; |
|
116 } |
|
117 } |
|
118 } else { |
|
119 if (WAVHeader.NumChannels == 2) { |
|
120 if (WAVHeader.BitsPerSample == 8) |
|
121 *format = AL_FORMAT_STEREO8; |
|
122 else { |
|
123 if (WAVHeader.BitsPerSample == 16) |
|
124 *format = AL_FORMAT_STEREO16; |
|
125 else { |
|
126 fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n"); |
|
127 return AL_FALSE; |
|
128 } |
|
129 } |
|
130 } else { |
|
131 fprintf(stderr, "ERROR: wrong WAV header - format value\n"); |
|
132 return AL_FALSE; |
|
133 } |
|
134 } |
|
135 |
|
136 *bitsize = WAVHeader.Subchunk2Size; |
|
137 *freq = WAVHeader.SampleRate; |
|
138 return AL_TRUE; |
|
139 } |
|
140 |
|
141 int load_OggVorbis (const char *filename, ALenum *format, uint8_t**data, ALsizei *bitsize, ALsizei *freq) { |
|
142 //implementation inspired from http://www.devmaster.net/forums/showthread.php?t=1153 |
|
143 FILE *oggFile; // ogg handle |
|
144 OggVorbis_File oggStream; // stream handle |
|
145 vorbis_info *vorbisInfo; // some formatting data |
|
146 vorbis_comment *vorbisComment; // other less useful data |
|
147 int64_t pcm_length; // length of the decoded data |
|
148 int size = 0; |
|
149 int section, result, i; |
|
150 |
|
151 oggFile = Fopen(filename, "rb"); |
|
152 result = ov_open(oggFile, &oggStream, NULL, 0); |
|
153 //TODO: check returning value of result |
|
154 |
|
155 vorbisInfo = ov_info(&oggStream, -1); |
|
156 pcm_length = ov_pcm_total(&oggStream,-1) << vorbisInfo->channels; |
|
157 |
|
158 #ifdef DEBUG |
|
159 vorbisComment = ov_comment(&oggStream, -1); |
|
160 fprintf(stderr, "Version: %d\n", vorbisInfo->version); |
|
161 fprintf(stderr, "Channels: %d\n", vorbisInfo->channels); |
|
162 fprintf(stderr, "Rate (Hz): %d\n", vorbisInfo->rate); |
|
163 fprintf(stderr, "Bitrate Upper: %d\n", vorbisInfo->bitrate_upper); |
|
164 fprintf(stderr, "Bitrate Nominal: %d\n", vorbisInfo->bitrate_nominal); |
|
165 fprintf(stderr, "Bitrate Lower: %d\n", vorbisInfo->bitrate_lower); |
|
166 fprintf(stderr, "Bitrate Windows: %d\n", vorbisInfo->bitrate_window); |
|
167 fprintf(stderr, "Vendor: %s\n", vorbisComment->vendor); |
|
168 fprintf(stderr, "PCM data size: %d\n", pcm_length); |
|
169 fprintf(stderr, "# comment: %d\n", vorbisComment->comments); |
|
170 for (i = 0; i < vorbisComment->comments; i++) |
|
171 fprintf(stderr, "\tComment %d: %s\n", i, vorbisComment->user_comments[i]); |
|
172 #endif |
|
173 |
|
174 //allocates enough room for the decoded data |
|
175 *data = (uint8_t*) malloc (sizeof(uint8_t) * pcm_length); |
|
176 |
|
177 //there *should* not be ogg at 8 bits |
|
178 if (vorbisInfo->channels == 1) |
|
179 *format = AL_FORMAT_MONO16; |
|
180 else { |
|
181 if (vorbisInfo->channels == 2) |
|
182 *format = AL_FORMAT_STEREO16; |
|
183 else { |
|
184 fprintf(stderr, "ERROR: wrong OGG header - channel value (%d)\n", vorbisInfo->channels); |
|
185 return AL_FALSE; |
|
186 } |
|
187 } |
|
188 |
|
189 while(size < pcm_length) { |
|
190 //ov_read decodes the ogg stream and storse the pcm in data |
|
191 result = ov_read (&oggStream, *data + size, pcm_length - size, 0, 2, 1, §ion); |
|
192 if(result > 0) { |
|
193 size += result; |
|
194 } else { |
|
195 if (result == 0) |
|
196 break; |
|
197 else { |
|
198 fprintf(stderr, "ERROR: end of file from OGG stream\n"); |
|
199 return AL_FALSE; |
|
200 } |
|
201 } |
|
202 } |
|
203 |
|
204 //records the last fields |
|
205 *bitsize = size; |
|
206 *freq = vorbisInfo->rate; |
|
207 return AL_TRUE; |
|
208 } |
|
209 |
|
210 #ifdef __CPLUSPLUS |
|
211 } |
|
212 #endif |