Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / ACMImporter / readers.cpp
blob54d954af6b473bf1f5372d2fe3942fb8f613395f
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 //#include "stdafx.h"
22 // Classes for sound files.
23 // Supported formats: PCM-RAW, PCM-WAV (both 8 and 16 bits),
24 // Ogg Vorbis and Interplay's ACM.
26 #include <stdio.h>
27 #include "Interface.h"
28 #include "readers.h"
29 #include "general.h"
31 #ifdef HAS_VORBIS_SUPPORT
32 static size_t ovfd_read(void *ptr, size_t size, size_t nmemb, void *datasource)
34 DataStream *vb = (DataStream *) datasource;
35 int bytesToRead = size * nmemb;
37 int remains = vb->Remains();
38 if(remains<=0) {
39 /* no more reading, we're at the end */
40 return 0;
42 if(bytesToRead > remains ) {
43 bytesToRead = remains;
45 vb->Read(ptr, bytesToRead);
46 return bytesToRead;
49 static int ovfd_seek(void *datasource, ogg_int64_t offset, int whence) {
50 DataStream *vb = (DataStream *) datasource;
51 switch(whence) {
52 case SEEK_SET:
53 if(vb->Seek(offset, GEM_STREAM_START)<0)
54 return -1;
55 break;
56 case SEEK_CUR:
57 if(vb->Seek(offset, GEM_CURRENT_POS)<0)
58 return -1;
59 break;
60 case SEEK_END:
61 if(vb->Seek(vb->Size()+offset, GEM_STREAM_START)<0)
62 return -1;
63 break;
64 default:
65 return -1;
67 return vb->GetPos();
70 static int ovfd_close(void * /*datasource*/) {
71 return 0;
74 static long ovfd_tell(void *datasource) {
75 DataStream *vb = (DataStream *) datasource;
76 return (long) vb->GetPos();
79 int COGGReader::init_reader()
81 vorbis_info *info;
82 int res;
83 ov_callbacks cbstruct = {
84 ovfd_read, ovfd_seek, ovfd_close, ovfd_tell
87 res=ov_open_callbacks(stream, &OggStream, NULL, 0, cbstruct);
88 if(res<0) {
89 printMessage("Sound","Couldn't initialize vorbis!\n", LIGHT_RED);
90 return 0;
92 info = ov_info(&OggStream, -1);
93 channels = info->channels;
94 samplerate = info->rate;
95 samples_left = ( samples = ov_pcm_total(&OggStream, -1) );
96 return 1;
99 void fix_endian(ieWord &dest);
101 int COGGReader::read_samples(short* buffer, int count)
103 int whatisthis;
105 if(samples_left<count) {
106 count=samples_left;
108 int samples_got=0;
109 int samples_need=count;
110 while(samples_need) {
111 int rd=ov_read(&OggStream, (char *)buffer, samples_need<<1, 0, 2, 1, &whatisthis);
112 if(rd==OV_HOLE) {
113 continue;
115 if(rd<=0) {
116 break;
118 rd>>=1;
119 buffer+=rd;
120 samples_got+=rd;
121 samples_need-=rd;
123 samples_left-=samples_got;
124 if (stream->IsEndianSwitch()) {
125 for (size_t i = 0; i < (size_t)samples_got; i++) {
126 fix_endian(((ieWord *)buffer-samples_got)[i]);
130 return samples_got;
133 #endif
135 int CACMReader::init_reader()
137 ACM_Header hdr;
138 char tmp[4];
140 stream->Read( tmp, sizeof( tmp ) );
141 if (!memcmp( tmp, "WAVC", 4 )) {
142 stream->Seek( 24, GEM_CURRENT_POS );
143 } else {
144 stream->Seek( -4, GEM_CURRENT_POS );
146 //stream->Read( &hdr, sizeof( ACM_Header ) );
147 //maybe this'll work on a PPC
149 stream->ReadDword( &hdr.signature );
150 stream->ReadDword( &hdr.samples );
151 stream->ReadWord( &hdr.channels );
152 stream->ReadWord( &hdr.rate );
153 ieWord tmpword;
154 stream->ReadWord( &tmpword );
155 //subblocks = (int) (tmpword&0xfff);
156 //levels = (int) (tmpword>>12);
157 subblocks = (int) (tmpword>>4);
158 levels = (int) (tmpword&15);
160 if (hdr.signature != IP_ACM_SIG) {
161 return 0;
163 samples_left = ( samples = hdr.samples );
164 channels = hdr.channels;
165 samplerate = hdr.rate;
166 //levels = hdr.levels;
167 //subblocks = hdr.subblocks;
169 block_size = ( 1 << levels ) * subblocks;
170 //using malloc for simple arrays (supposed to be faster)
171 block = (int *) malloc(sizeof(int)*block_size);
172 if (!block) {
173 return 0;
175 unpacker = new CValueUnpacker( levels, subblocks, stream );
176 if (!unpacker || !unpacker->init_unpacker()) {
177 return 0;
179 decoder = new CSubbandDecoder( levels );
180 if (!decoder || !decoder->init_decoder()) {
181 return 0;
183 return 1;
185 int CACMReader::make_new_samples()
187 if (!unpacker->get_one_block( block )) {
188 return 0;
191 decoder->decode_data( block, subblocks );
192 values = block;
193 samples_ready = ( block_size > samples_left ) ? samples_left : block_size;
194 samples_left -= samples_ready;
196 return 1;
199 int CACMReader::read_samples(short* buffer, int count)
201 int res = 0;
202 while (res < count) {
203 if (samples_ready == 0) {
204 if (samples_left == 0)
205 break;
206 if (!make_new_samples())
207 break;
209 *buffer = ( short ) ( ( *values ) >> levels );
210 values++;
211 buffer++;
212 res += 1;
213 samples_ready--;
215 return res;
218 CSoundReader* CreateSoundReader(DataStream* stream, int type, int samples,
219 bool autoFree)
221 CSoundReader* res = NULL;
223 switch (type) {
224 #ifdef HAS_VORBIS_SUPPORT
225 case SND_READER_OGG:
226 res = new COGGReader( stream, autoFree );
227 break;
228 #endif
229 case SND_READER_ACM:
230 res = new CACMReader( stream, autoFree );
231 break;
232 case SND_READER_WAV:
233 res = new CWavPCMReader( stream, samples, autoFree );
234 break;
235 default:
236 if (autoFree) delete stream;
237 break;
239 if (res) {
240 if (!res->init_reader()) {
241 delete res;
242 res = NULL;
245 return res;
248 int CRawPCMReader::init_reader()
250 if (samples < 0) {
251 samples = stream->Size();
252 stream->Seek( 0, GEM_STREAM_START );
253 if (is16bit) {
254 samples >>= 1; // each sample has 16 bit
257 samples_left = samples;
258 return 1;
261 inline void fix_endian(ieDword &dest)
263 unsigned char tmp;
264 tmp=((unsigned char *) &dest)[0];
265 ((unsigned char *) &dest)[0]=((unsigned char *) &dest)[3];
266 ((unsigned char *) &dest)[3]=tmp;
267 tmp=((unsigned char *) &dest)[1];
268 ((unsigned char *) &dest)[1]=((unsigned char *) &dest)[2];
269 ((unsigned char *) &dest)[2]=tmp;
273 inline void fix_endian(ieWord &dest)
275 unsigned char tmp;
276 tmp=((unsigned char *) &dest)[0];
277 ((unsigned char *) &dest)[0]=((unsigned char *) &dest)[1];
278 ((unsigned char *) &dest)[1]=tmp;
282 int CRawPCMReader::read_samples(short* buffer, int count)
284 if (count > samples_left) {
285 count = samples_left;
287 int res = 0;
288 if (count) {
289 res = stream->Read( buffer, count * ( ( is16bit ? 2 : 1 ) ) );
291 if (!is16bit) {
292 char* alt_buff = ( char* ) buffer;
293 int i = res;
294 while(i--) {
295 alt_buff[( i << 1 ) + 1] = ( char ) ( alt_buff[i] - 0x80 );
296 alt_buff[i << 1] = 0;
299 if(is16bit) {
300 res >>= 1;
301 if (stream->IsEndianSwitch()) {
302 for (size_t i = 0; i < (size_t)count; i++) {
303 fix_endian(((ieWord *)buffer)[i]);
307 samples_left -= res;
308 return res;
311 int CWavPCMReader::init_reader()
313 int res = CRawPCMReader::init_reader(); if (!res) {
314 return res;
317 cWAVEFORMATEX fmt;
318 RIFF_CHUNK r_hdr, fmt_hdr, data_hdr;
319 unsigned int wave;
320 memset( &fmt, 0, sizeof( fmt ) );
322 //stream->Read( &r_hdr, sizeof( r_hdr ) );
323 //don't swap this
324 stream->Read(&r_hdr.fourcc, 4);
325 stream->ReadDword(&r_hdr.length);
326 //don't swap this
327 stream->Read( &wave, 4 );
328 if (r_hdr.fourcc != *( unsigned int * ) RIFF_4cc ||
329 wave != *( unsigned int * ) WAVE_4cc) {
330 return 0;
333 //stream->Read( &fmt_hdr, sizeof( fmt_hdr ) );
334 //don't swap this
335 stream->Read(&fmt_hdr.fourcc,4);
336 stream->ReadDword(&fmt_hdr.length);
337 if (fmt_hdr.fourcc != *( unsigned int * ) fmt_4cc ||
338 fmt_hdr.length > sizeof( cWAVEFORMATEX )) {
339 return 0;
341 memset(&fmt,0,sizeof(fmt) );
342 stream->Read( &fmt, fmt_hdr.length );
343 //hmm, we should swap fmt bytes if we are on a mac
344 //but we don't know exactly how much of the structure we'll read
345 //so we have to swap the bytes after reading them
346 if (stream->IsEndianSwitch()) {
347 fix_endian(fmt.wFormatTag);
348 fix_endian(fmt.nChannels);
349 fix_endian(fmt.nSamplesPerSec);
350 fix_endian(fmt.wBitsPerSample);
351 //we don't use these fields, so who cares
352 //fix_endian(fmt.nAvgBytesPerSec);
353 //fix_endian(fmt.nBlockAlign);
354 //fix_endian(fmt.cbSize);
356 if (fmt.wFormatTag != 1) {
357 return 0;
359 is16bit = ( fmt.wBitsPerSample == 16 );
361 //stream->Read( &data_hdr, sizeof( data_hdr ) );
362 //don't swap this
363 stream->Read(&data_hdr.fourcc,4);
364 stream->ReadDword(&data_hdr.length);
366 if (data_hdr.fourcc == *( unsigned int * ) fact_4cc) {
367 stream->Seek( data_hdr.length, GEM_CURRENT_POS );
368 //stream->Read( &data_hdr, sizeof( data_hdr ) );
369 stream->ReadDword(&data_hdr.fourcc);
370 stream->ReadDword(&data_hdr.length);
372 if (data_hdr.fourcc != *( unsigned int * ) data_4cc) {
373 return 0;
376 samples = data_hdr.length;
377 if (is16bit) {
378 samples >>= 1;
380 samples_left = samples;
381 channels = fmt.nChannels;
382 samplerate = fmt.nSamplesPerSec;
383 return 1;