00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <sstream>
00021 #include <fstream>
00022 #include <stdexcept>
00023
00024 #include "channel.h"
00025 #include "endian.h"
00026 #include "chunck.h"
00027 #include "chunck_type.h"
00028
00029 #ifdef DEBUG_CHANNEL
00030 #include <iostream>
00031 #include <iomanip>
00032 #endif
00033
00034
00035 using namespace std;
00036
00037 void saud_channel::handleStrk(chunck & b) throw(exception) {
00038 int size = b.get_size();
00039 if(size != 14 && size != 10) {
00040 ostringstream oss;
00041 oss << "STRK has a invalid size : " << size;
00042 throw runtime_error(oss.str());
00043 }
00044 #ifdef DEBUG_CHANNEL
00045 int unk1 = b.get_byte();
00046 int unk2 = b.get_byte();
00047 int unk3 = from_big_endian(b.get_dword());
00048 int unk4 = from_big_endian(b.get_dword());
00049 cout << "TRACK " << _track << " STRK(" << size << ") content : ";
00050 cout << unk1 << " " << unk2 << " " << unk3 << " "<< unk4;
00051 if(size == 14) {
00052 int unk5 = from_big_endian(b.get_dword());
00053 cout << " " << unk5;
00054 }
00055 cout << endl;
00056 #endif
00057 }
00058
00059 void saud_channel::handleSmrk(chunck & b) throw(exception) {
00060 #ifdef DEBUG_CHANNEL
00061 int size = b.get_size();
00062 if(size > 0)
00063 {
00064 cout << "TRACK " << _track << " SMRK(" << size << ") content : ";
00065 for(int i = 0; i < size; i++) {
00066 cout << setw(3) << static_cast<int>(b.get_byte()) << " ";
00067 }
00068 cout << endl;
00069 }
00070 #endif
00071 _mark_reached = true;
00072 }
00073
00074 void saud_channel::handleShdr(chunck & b) throw(exception) {
00075 int size = b.get_size();
00076 if(size != 4) throw runtime_error("SMRK has a invalid size");
00077 #ifdef DEBUG_CHANNEL
00078 int unknown = b.get_dword();
00079 cout << "TRACK " << _track << " SHDR(" << size << ") content : " << unknown << endl;
00080 #endif
00081 }
00082
00083 bool saud_channel::processBuffer() throw(exception) {
00084 #ifdef DEBUG_CHANNEL
00085 cout << "processBuffer(" << _track << ") : _cur_buffer_write_pos " << _cur_buffer_write_pos << ", _cur_buffer_read_pos " << _cur_buffer_read_pos << endl;
00086 #endif
00087 while((_cur_buffer_write_pos - _cur_buffer_read_pos) > 8) {
00088 int available_size = _cur_buffer_write_pos - _cur_buffer_read_pos;
00089 chunck::type type = from_big_endian(*reinterpret_cast<unsigned int *>(_buffer + _cur_buffer_read_pos));
00090 unsigned int size = from_big_endian(*reinterpret_cast<unsigned int *>(_buffer + _cur_buffer_read_pos + 4));
00091 #ifdef DEBUG_CHANNEL
00092 cout << "TRACK " << _track << ", chunck " << chunck::chunck_string(type) << ", " << available_size << "/" << size+8 << endl;
00093 #endif
00094 cont_chunck * c = 0;
00095 switch(type) {
00096 case TYPE_STRK:
00097 assert(available_size >= (size + 8));
00098 c = new cont_chunck(reinterpret_cast<char*>(_buffer) + _cur_buffer_read_pos);
00099 handleStrk(*c);
00100 break;
00101 case TYPE_SMRK:
00102 assert(available_size >= (size + 8));
00103 c = new cont_chunck(reinterpret_cast<char*>(_buffer) + _cur_buffer_read_pos);
00104 handleSmrk(*c);
00105 break;
00106 case TYPE_SHDR:
00107 assert(available_size >= (size + 8));
00108 c = new cont_chunck(reinterpret_cast<char*>(_buffer) + _cur_buffer_read_pos);
00109 handleShdr(*c);
00110 break;
00111 case TYPE_SDAT:
00112 if(_data_start == -1) {
00113 _rdata_start = _data_start = _cur_buffer_read_pos + 8;
00114 _rdata_size = _data_size = size;
00115 }
00116 break;
00117 default:
00118 ostringstream oss;
00119 oss << "unknown chunck in SAUD track : " << chunck::chunck_string(type) << endl;
00120 throw(runtime_error(oss.str()));
00121 }
00122 if(c) delete c;
00123 if(available_size >= (size + 8)) {
00124 _cur_buffer_read_pos += size + 8;
00125 } else break;
00126 }
00127 return true;
00128 }
00129
00130 saud_channel::saud_channel(int track, int freq) throw() :
00131 _track(track),
00132 _nbframes(0),
00133 _buffer(0),
00134 _buffer_size(0),
00135 _frequency(freq),
00136 _cur_buffer_write_pos(0),
00137 _cur_buffer_read_pos(0),
00138 _data_start(-1),
00139 _mark_reached(false) {
00140 }
00141
00142 extern bool win32_save_as_wave(const string & fname, char * data, int size, int freq);
00143
00144 saud_channel::~saud_channel() throw() {
00145 #ifdef DEBUG_CHANNEL
00146 cout << "~saud_channel(" << _track << ") size == " << _buffer_size << ", _cur_buffer_write_pos == " << _cur_buffer_write_pos << endl;
00147 #endif
00148 #if 0
00149 ostringstream oss;
00150 oss << "track" << _track << "_" << _flags << "_" << _volume << ".wav";
00151 win32_save_as_wave(oss.str(), reinterpret_cast<char *>(_buffer) + _rdata_start, _rdata_size, _frequency);
00152 #endif
00153 if(_buffer) {
00154 delete []_buffer;
00155 }
00156 }
00157
00158 bool saud_channel::is_terminated() const throw() {
00159 #ifdef DEBUG_CHANNEL
00160 cout << "saud_channel::is_terminated() : " << _cur_buffer_read_pos << ", " << _buffer_size << ", " << _data_start << ", " << _data_size << endl;
00161 #endif
00162 if(_cur_buffer_read_pos < _buffer_size) return false;
00163 if(_data_start != -1 && _data_size == 0) return true;
00164 return false;
00165 }
00166
00167 void saud_channel::recalcVolumeTable() throw(exception) {
00168 const int MAX_BALANCE = 100;
00169 int volume_left, volume_right;
00170 if(_balance < -MAX_BALANCE || _balance > MAX_BALANCE) {
00171 ostringstream oss;
00172 oss << "balance is out of range ! : " << _balance;
00173 throw runtime_error(oss.str());
00174 }
00175 int left_multiplier = MAX_BALANCE - _balance;
00176 int right_multiplier = MAX_BALANCE + _balance;
00177 volume_left = _volume * left_multiplier / (MAX_BALANCE*2);
00178 volume_right = _volume * right_multiplier / (MAX_BALANCE*2);
00179 if(volume_left < 0) volume_left = 0;
00180 if(volume_left > 128) volume_left = 128;
00181 if(volume_right < 0) volume_right = 0;
00182 if(volume_right > 128) volume_right = 128;
00183 for(int i = 0; i < 256; i++) {
00184 _voltable[0][i] = volume_left * static_cast<signed char>(i);
00185 _voltable[1][i] = volume_right * static_cast<signed char>(i);
00186 }
00187 }
00188
00189 bool saud_channel::set_parameters(int nb, int flags, int volume, int balance) throw(exception) {
00190 if(_nbframes || _buffer) throw(runtime_error("channel initialized twice"));
00191 _nbframes = nb;
00192 _flags = flags;
00193 _volume = volume;
00194 _balance = balance;
00195 _index = 0;
00196
00197 recalcVolumeTable();
00198
00199
00200 return true;
00201 }
00202
00203 bool saud_channel::check_parameters(int index, int nb, int flags, int volume, int balance) throw(exception) {
00204 if(++_index != index) throw runtime_error("invalid index in saud_channel::check_parameters()");
00205 if(_nbframes != nb) throw runtime_error("invalid duration in saud_channel::check_parameters()");
00206 if(_flags != flags) throw runtime_error("invalid flags in saud_channel::check_parameters()");
00207 if(_volume != volume || _balance != balance) {
00208
00209 _volume = volume;
00210 _balance = balance;
00211
00212 recalcVolumeTable();
00213 }
00214 return true;
00215 }
00216
00217 bool saud_channel::append_data(chunck & b, int size) throw(exception) {
00218 if(!_buffer) {
00219 assert(size > 8);
00220 chunck::type saud_type = from_big_endian(b.get_dword());
00221 unsigned int saud_size = from_big_endian(b.get_dword());
00222 if(saud_type != TYPE_SAUD) throw(runtime_error("Invalid CHUNCK for saud_channel"));
00223 size -= 8;
00224 _buffer_size = saud_size;
00225 assert(_buffer_size);
00226 _buffer = new unsigned char[_buffer_size];
00227 if(!_buffer) throw(runtime_error("saud_channel failed to allocate memory"));
00228 b.read(_buffer, size);
00229 _cur_buffer_write_pos = size;
00230 } else {
00231 assert(size <= (_buffer_size - _cur_buffer_write_pos));
00232 b.read(_buffer + _cur_buffer_write_pos, size);
00233 _cur_buffer_write_pos += size;
00234 }
00235 return processBuffer();
00236 }
00237
00238 void saud_channel::read_sound_data(short * snd, int size) throw(std::exception) {
00239 if(_data_start == -1 || _data_size == 0) throw(runtime_error("invalid call to saud_channel::read_sound_data()"));
00240
00241 #ifdef DEBUG_CHANNEL
00242 int available = min(_cur_buffer_write_pos - _data_start, _data_size);
00243 cout << "saud_channel::read_sound_data(" << _track << ") size == " << size << ", available == " << available << endl;
00244 assert(available >= size);
00245 #endif
00246 for(int i = 0; i < size; i++) {
00247 snd[2*i] += _voltable[0][_buffer[_data_start+i] ^ 0x80];
00248 snd[2*i+1] += _voltable[1][_buffer[_data_start+i] ^ 0x80];
00249 }
00250 _data_start += size;
00251 _data_size -= size;
00252 }
00253
00254 int saud_channel::available_sound_data(void) const throw() {
00255 return min(_cur_buffer_write_pos - _data_start, _data_size);
00256 }
00257
00258 imuse_channel::imuse_channel(int track, int freq) throw() :
00259 _track(track),
00260 _buffer(0),
00261 _buffer_size(0),
00262 _frequency(freq),
00263 _cur_buffer_write_pos(0),
00264 _cur_buffer_read_pos(0),
00265 _data_start(-1){
00266 _decoded_buffer = new short[_frequency*2];
00267 assert(_decoded_buffer);
00268 _resampled_buffer = new short[_frequency*2];
00269 assert(_resampled_buffer);
00270 }
00271
00272 imuse_channel::~imuse_channel() throw() {
00273 #ifdef DEBUG_CHANNEL
00274 cout << "~imuse_channel(" << _track << ") size == " << _buffer_size << ", _cur_buffer_write_pos == " << _cur_buffer_write_pos << endl;
00275 #endif
00276 #if 0
00277 ofstream o;
00278 ostringstream oss;
00279 oss << "track" << _track << "_" << _unk1 << "_" << _unk2 << ".dat";
00280 o.open(oss.str().c_str(), ios::out|ios::binary);
00281 o.write(reinterpret_cast<char*>(_buffer), _buffer_size);
00282 o.close();
00283 #endif
00284 if(_buffer) {
00285 delete []_buffer;
00286 }
00287 delete []_resampled_buffer;
00288 delete []_decoded_buffer;
00289 }
00290
00291 bool imuse_channel::is_terminated() const throw()
00292 {
00293
00294
00295 if(_cur_buffer_read_pos < (_buffer_size - 8)) return false;
00296 if(_data_start != -1 && available_sound_data() == 0) return true;
00297 return false;
00298 }
00299
00300 bool imuse_channel::set_parameters(int nbframes, int size, int unk1, int unk2) throw(std::exception)
00301 {
00302 #ifdef DEBUG_CHANNEL
00303 cout << "imuse_channel::set_parameters(" << _track << ", " << nbframes<< ", " << size<< ", " << unk1<< ", " << unk2 << ")" << endl;
00304 #endif
00305 _nbframes = nbframes;
00306 _size = size;
00307 _unk1 = unk1;
00308 _unk2 = unk2;
00309 _index = 0;
00310 return true;
00311 }
00312
00313 bool imuse_channel::check_parameters(int index, int nbframes, int size, int unk1, int unk2) throw(std::exception)
00314 {
00315 #ifdef DEBUG_CHANNEL
00316 cout << "imuse_channel::check_parameters(" <<
00317 index << ", " <<
00318 nbframes << ", " <<
00319 size << ", " <<
00320 unk1 << ", " <<
00321 unk2 << ") == " <<
00322 _track << ", " <<
00323 _index+1 << ", " <<
00324 _nbframes << ", " <<
00325 _size << ", " <<
00326 _unk1 << ", " <<
00327 _unk2 << endl;
00328 if(++_index != index) throw runtime_error("invalid index in imuse_channel::check_parameters()");
00329 if(_nbframes != nbframes) throw runtime_error("invalid nbframes in imuse_channel::check_parameters()");
00330 if(_size != size) throw runtime_error("invalid size in imuse_channel::check_parameters()");
00331 if(_unk1 != unk1) throw runtime_error("invalid unk1 in imuse_channel::check_parameters()");
00332 if(_unk2 != unk2) throw runtime_error("invalid unk2 in imuse_channel::check_parameters()");
00333
00334 #endif
00335 return true;
00336 }
00337
00338 bool imuse_channel::append_data(chunck & b, int size) throw(std::exception)
00339 {
00340 #ifdef DEBUG_CHANNEL
00341 cout << "imuse_channel::append_data(" << _track << ") : " << size << " < " << _buffer_size<< endl;
00342 #endif
00343 _size -= size;
00344 if(!_buffer) {
00345 assert(size > 8);
00346 chunck::type imus_type = from_big_endian(b.get_dword());
00347 unsigned int imus_size = from_big_endian(b.get_dword());
00348 if(imus_type != TYPE_iMUS) throw runtime_error("Invalid CHUNCK for imuse_channel");
00349 size -= 8;
00350 _buffer_size = imus_size;
00351 assert(_buffer_size);
00352 _buffer = new unsigned char[_buffer_size];
00353 if(!_buffer) throw runtime_error("imuse_channel failed to allocate memory");
00354 b.read(_buffer, size);
00355 _cur_buffer_write_pos = size;
00356 } else {
00357 #ifdef DEBUG_CHANNEL
00358 if(size > (_buffer_size - _cur_buffer_write_pos))
00359 cerr << "imuse_channel::append_data(" << _track << ") : " << size << " > " << _buffer_size - _cur_buffer_write_pos << endl;
00360 #endif
00361
00362 assert(size <= (_buffer_size - _cur_buffer_write_pos));
00363
00364 b.read(_buffer + _cur_buffer_write_pos, size);
00365 _cur_buffer_write_pos += size;
00366 }
00367 return processBuffer();
00368 }
00369
00370 bool imuse_channel::handleFormat(chunck & src) {
00371 if(src.get_size() != 20) throw runtime_error("invalid size for FRMT chunck");
00372 _imuse_start = from_big_endian(src.get_dword());
00373 #ifdef DEBUG_CHANNEL
00374 int unknown = from_big_endian(src.get_dword());
00375 #else
00376 src.seek(4);
00377 #endif
00378 _bitsize = from_big_endian(src.get_dword());
00379 _rate = from_big_endian(src.get_dword());
00380 _channels = from_big_endian(src.get_dword());
00381 assert(_channels == 1 || _channels == 2);
00382 #ifdef DEBUG_CHANNEL
00383 if(unknown != 0) cerr << "imuse_channel::handleFormat() == " << unknown << ", " << _imuse_start << ", " << _bitsize << ", " << _rate << ", " << _channels << endl;
00384 #endif
00385 return true;
00386 }
00387
00388 bool imuse_channel::handleText(chunck & src) {
00389
00390 #ifdef DEBUG_CHANNEL
00391 int start = from_big_endian(src.get_dword());
00392 assert(start == _imuse_start);
00393 int text_size = src.get_size() - 4;
00394 char * buf = new char[text_size];
00395 src.read(buf, text_size);
00396 string text(buf, text_size);
00397 delete []buf;
00398 assert(text.size() == text_size);
00399 #endif
00400
00401 return true;
00402 }
00403
00404 bool imuse_channel::handleRegion(chunck & src) {
00405 if(src.get_size() != 8) throw runtime_error("invalid size for REGN chunck");
00406 #ifdef DEBUG_CHANNEL
00407 int start = from_big_endian(src.get_dword());
00408 assert(start == _imuse_start);
00409 #else
00410 src.seek(4);
00411 #endif
00412 _imuse_length = from_big_endian(src.get_dword());
00413
00414 return true;
00415 }
00416
00417 bool imuse_channel::handleStop(chunck & src) {
00418 if(src.get_size() != 4) throw runtime_error("invalid size for STOP chunck");
00419 #ifdef DEBUG_CHANNEL
00420 int _imuse_stop = from_big_endian(src.get_dword());
00421 assert(_imuse_stop == _imuse_start + _imuse_length);
00422 #endif
00423 return true;
00424 }
00425
00426 bool imuse_channel::handleMap(chunck & map) {
00427 while(!map.eof()) {
00428 chunck * sub = map.sub_block();
00429
00430 switch(sub->get_type()) {
00431 case TYPE_FRMT:
00432 handleFormat(*sub);
00433 break;
00434 case TYPE_TEXT:
00435 handleText(*sub);
00436 break;
00437 case TYPE_REGN:
00438 handleRegion(*sub);
00439 break;
00440 case TYPE_STOP:
00441 handleStop(*sub);
00442 break;
00443 default:
00444 ostringstream oss;
00445 oss << "Unknown iMUS subchunck found : " << chunck::chunck_string(sub->get_type()) << ", " << sub->get_size();
00446 throw runtime_error(oss.str());
00447 }
00448 delete sub;
00449 }
00450 return true;
00451 }
00452
00453 int imuse_channel::resample_mono(int size) throw(std::exception)
00454 {
00455
00456 if(_rate > _frequency) throw runtime_error("Unsupported : imuse rate > output frequency");
00457 int multiplier = _frequency / _rate;
00458
00459 if((_rate * multiplier) != _frequency) throw runtime_error("Unsupported : imuse rate is not a multiple of output frequency");
00460 multiplier *= 2;
00461 assert(size * multiplier < _frequency*2);
00462 short * decoded = _decoded_buffer;
00463 short * resampled = _resampled_buffer;
00464 if(multiplier == 2) {
00465 for(int i = 0; i < size; i++) {
00466 *resampled++ = *decoded;
00467 *resampled++ = *decoded++;
00468 }
00469 return size * 2;
00470 } else if(multiplier == 4) {
00471 for(int i = 0; i < size; i++) {
00472 *resampled++ = *decoded;
00473 *resampled++ = *decoded;
00474 *resampled++ = *decoded;
00475 *resampled++ = *decoded++;
00476 }
00477 return size * 4;
00478 } else {
00479 #ifdef DEBUG_CHANNEL
00480 cerr << "imuse_channel::resample() multiplier == " << multiplier << endl;
00481 #endif
00482 for(int i = 0; i < size; i++) {
00483 for(int x = 0; x < multiplier; x++) {
00484 *resampled++ = *decoded;
00485 }
00486 decoded++;
00487 }
00488 return resampled - _resampled_buffer;
00489 }
00490 }
00491
00492 int imuse_channel::resample_stereo(int size) throw(std::exception)
00493 {
00494 assert((size & 1) == 0);
00495
00496 if(_rate > _frequency) throw runtime_error("Unsupported : imuse rate > output frequency");
00497 int multiplier = _frequency / _rate;
00498
00499 if((_rate * multiplier) != _frequency) throw runtime_error("Unsupported : imuse rate is not a multiple of output frequency");
00500 if(_channels == 1) multiplier *= 2;
00501 assert(size * multiplier < _frequency*2);
00502 short * decoded = _decoded_buffer;
00503 short * resampled = _resampled_buffer;
00504 if(multiplier == 1) {
00505 memcpy(resampled, decoded, size * sizeof(short));
00506 return size;
00507 } else if(multiplier == 2) {
00508 size /= 2;
00509 for(int i = 0; i < size; i++) {
00510 short v1 = *decoded++;
00511 short v2 = *decoded++;
00512 *resampled++ = v1;
00513 *resampled++ = v2;
00514 *resampled++ = v1;
00515 *resampled++ = v2;
00516 }
00517 return size * 4;
00518 } else {
00519 #ifdef DEBUG_CHANNEL
00520 cerr << "imuse_channel::resample() multiplier == " << multiplier << endl;
00521 #endif
00522 size /= 2;
00523 for(int i = 0; i < size; i++) {
00524 short v1 = *decoded++;
00525 short v2 = *decoded++;
00526 for(int x = 0; x < multiplier; x++) {
00527 *resampled++ = v1;
00528 *resampled++ = v2;
00529 }
00530 }
00531 return resampled - _resampled_buffer;
00532 }
00533 }
00534
00535 int imuse_channel::decode(int size, int &ret) throw(std::exception)
00536 {
00537 short * decoded = _decoded_buffer;
00538 unsigned char * source = _buffer + _data_start;
00539
00540 switch(_bitsize) {
00541 case 8:
00542 while(size--) {
00543 *decoded++ = (static_cast<short>(*source++) - 128) << 8;
00544 } break;
00545 case 12:
00546
00547 {
00548 int msize = size & 1;
00549 size = (size+1) >> 1;
00550 while(size--) {
00551 int v1 = *source++;
00552 int v2 = *source++;
00553 int v3 = *source++;
00554 int value = (((v2 & 0x0f) << 12) | (v1 << 4)) - 0x8000;
00555 *decoded++ = static_cast<short>(value);
00556 value = (((v2 & 0xf0) << 8) | (v3 << 4)) - 0x8000;
00557 *decoded++ = static_cast<short>(value);
00558 }
00559 if(msize) {
00560 decoded--;
00561 #ifdef DEBUG_CHANNEL
00562 cerr << "imuse_channel::decode() had to skip a sample..." << endl;
00563 #endif
00564 }
00565 } break;
00566 case 16:
00567 while(size--) {
00568 int value = ((*source++ << 8) + *source++) - 0x8000;
00569 *decoded++ = static_cast<short>(value);
00570 } break;
00571 default:
00572 throw runtime_error("Unsupported bit size in imuse chunck");
00573 }
00574 ret = source - (_buffer + _data_start);
00575 return decoded - _decoded_buffer;
00576 }
00577
00578 bool imuse_channel::processBuffer() throw(exception) {
00579 #ifdef DEBUG_CHANNEL
00580 cout << "imuse_channel::processBuffer(" << _track << ") : _cur_buffer_write_pos " << _cur_buffer_write_pos << ", _cur_buffer_read_pos " << _cur_buffer_read_pos << endl;
00581 #endif
00582 while((_cur_buffer_write_pos - _cur_buffer_read_pos) >= 8) {
00583 int available_size = _cur_buffer_write_pos - _cur_buffer_read_pos;
00584 chunck::type type = from_big_endian(*reinterpret_cast<unsigned int *>(_buffer + _cur_buffer_read_pos));
00585 unsigned int size = from_big_endian(*reinterpret_cast<unsigned int *>(_buffer + _cur_buffer_read_pos + 4));
00586 #ifdef DEBUG_CHANNEL
00587 cout << "TRACK " << _track << ", chunck " << chunck::chunck_string(type) << ", " << available_size << "/" << size+8 << endl;
00588 #endif
00589 switch(type) {
00590 case TYPE_MAP_:
00591 {
00592 assert(available_size >= (size + 8));
00593 cont_chunck map_chunck(reinterpret_cast<char*>(_buffer) + _cur_buffer_read_pos);
00594 handleMap(map_chunck);
00595 } break;
00596 case TYPE_DATA:
00597 if(_data_start == -1) {
00598 _rdata_start = _data_start = _cur_buffer_read_pos + 8;
00599 _rdata_size = _data_size = size;
00600 int reqsize = 1;
00601 if(_channels == 2) reqsize *= 2;
00602 if(_bitsize == 16) reqsize *= 2;
00603 else if(_bitsize == 12) reqsize *= 3;
00604 if((size % reqsize) != 0)
00605 throw runtime_error("Invalid sound data size");
00606 }
00607 break;
00608 case TYPE_iMUS:
00609 size = 0;
00610 break;
00611 default:
00612 {
00613 ostringstream oss;
00614 oss << "unknown chunck in iMUS track : " << chunck::chunck_string(type) << endl;
00615 throw runtime_error(oss.str());
00616 } break;
00617 }
00618
00619 if(available_size >= (size + 8)) {
00620 _cur_buffer_read_pos += size + 8;
00621 } else {
00622 break;
00623 }
00624 }
00625 return true;
00626 }
00627
00628 int imuse_channel::available_sound_data(void) const throw() {
00629 assert(_data_start <= _cur_buffer_write_pos);
00630 int size = min(_cur_buffer_write_pos - _data_start, _data_size);
00631
00632
00633 switch(_bitsize) {
00634 case 12:
00635 size = (size / 3) * 2;
00636 break;
00637 case 16:
00638 size /= 2;
00639 }
00640 if(_channels == 2)
00641 size /= 2;
00642 if(_bitsize == 12) size &= ~1;
00643
00644 return size;
00645 }
00646
00647 void imuse_channel::read_sound_data(short * snd, int size) throw(std::exception) {
00648 if(_data_start == -1 || _data_size == 0) throw(runtime_error("invalid call to saud_channel::read_sound_data()"));
00649
00650 #ifdef DEBUG_CHANNEL
00651 int available = min(_cur_buffer_write_pos - _data_start, _data_size) * 2;
00652 switch(_bitsize) {
00653 case 12:
00654 available = (available / 3) * 2;
00655 break;
00656 case 16:
00657 available /= 2;
00658 }
00659 cout << "saud_channel::read_sound_data(" << _track << ") size == " << size << ", available == " << available << endl;
00660 assert(available >= size);
00661 #endif
00662
00663
00664 int resampled_size, really_decoded = 0;
00665 int decoded_size = decode((_channels == 2) ? size*2 : size, really_decoded);
00666 _data_start += really_decoded;
00667 _data_size -= really_decoded;
00668 if(_channels == 2)
00669 resampled_size = resample_stereo(decoded_size);
00670 else
00671 resampled_size = resample_mono(decoded_size);
00672 #ifdef DEBUG_CHANNEL
00673 cerr << "imuse::write() size * 2 == " << size * 2 << ", resampled_size == " << resampled_size << endl;
00674 #endif
00675
00676 for(int i = 0; i < size * 2; i++)
00677 snd[i] += _resampled_buffer[i];
00678 }
00679
00680
00681