1 /* 2 3 SynthFileReader.cpp 4 5 Copyright (c) 2002 Haiku. 6 7 8 Author: 9 Michael Pfeiffer 10 11 Permission is hereby granted, free of charge, to any person obtaining a copy of 12 this software and associated documentation files (the "Software"), to deal in 13 the Software without restriction, including without limitation the rights to 14 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 15 of the Software, and to permit persons to whom the Software is furnished to do 16 so, subject to the following conditions: 17 18 The above copyright notice and this permission notice shall be included in all 19 copies or substantial portions of the Software. 20 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 THE SOFTWARE. 28 29 */ 30 31 #include "SynthFileReader.h" 32 #include "SynthFile.h" 33 #include <string.h> 34 #include <ctype.h> 35 36 #define DEBUG 1 37 #include <Debug.h> 38 39 SSynthFileReader::SSynthFileReader(const char* synthFile) { 40 fFile = fopen(synthFile, "r+b"); 41 tag tag; 42 if (fFile) { 43 if (Read(tag) && TagEquals(tag, "IREZ")) { 44 return; 45 } 46 fclose(fFile); fFile = NULL; 47 } 48 49 } 50 51 SSynthFileReader::~SSynthFileReader() { 52 if (fFile) { 53 fclose(fFile); fFile = NULL; 54 } 55 } 56 57 status_t SSynthFileReader::InitCheck() const { 58 return fFile != NULL ? B_OK : B_ERROR; 59 } 60 61 bool SSynthFileReader::TagEquals(const char* tag1, const char* tag2) const { 62 return strncmp(tag1, tag2, 4) == 0; 63 } 64 65 bool SSynthFileReader::Read(void* data, uint32 size) { 66 return 1 == fread(data, size, 1, fFile); 67 } 68 69 bool SSynthFileReader::Read(tag &tag) { 70 return Read((void*)tag, sizeof(tag)); 71 } 72 73 bool SSynthFileReader::Read(uint64 &n, uint32 size) { 74 uint8 number[8]; 75 ASSERT(size <= sizeof(number)); 76 if (Read((void*)number, size)) { 77 n = 0; 78 for (unsigned int i = 0; i < size; i ++) { 79 n <<= 8; 80 n += number[i]; 81 } 82 return true; 83 } 84 return false; 85 } 86 87 bool SSynthFileReader::Read(uint32 &n) { 88 uint64 num; 89 bool ok = Read(num, 4); 90 n = num; 91 return ok; 92 } 93 94 95 bool SSynthFileReader::Read(uint16 &n) { 96 uint64 num; 97 bool ok = Read(num, 2); 98 n = num; 99 return ok; 100 } 101 102 103 bool SSynthFileReader::Read(uint8 &n) { 104 return Read((void*)&n, 1); 105 } 106 107 bool SSynthFileReader::Read(BString& s, uint32 len) { 108 char* str = s.LockBuffer(len+1); 109 str[len] = 0; 110 bool ok = Read((void*)str, len); 111 s.UnlockBuffer(len+1); 112 return ok; 113 } 114 115 bool SSynthFileReader::Skip(uint32 bytes) { 116 fseek(fFile, bytes, SEEK_CUR); 117 return true; 118 } 119 120 121 bool SSynthFileReader::ReadHeader(uint32& version, uint32& chunks, uint32& nextChunk) { 122 tag tag; 123 fseek(fFile, 0, SEEK_SET); 124 if (Read(tag) && TagEquals(tag, "IREZ") && Read(version) && Read(chunks)) { 125 nextChunk = ftell(fFile); 126 return true; 127 } 128 return false; 129 } 130 131 132 bool SSynthFileReader::NextChunk(tag& tag, uint32& nextChunk) { 133 fseek(fFile, nextChunk, SEEK_SET); 134 return Read(nextChunk) && Read(tag); 135 } 136 137 138 bool SSynthFileReader::ReadInstHeader(uint16& inst, uint16& snd, uint16& snds, BString& name, uint32& size) { 139 uint8 len; 140 141 if (Skip(2) && Read(inst) && Read(len) && Read(name, len) && Read(size) && Read(snd) && Skip(10) && Read(snds)) { 142 size -= 14; 143 return true; 144 } 145 return false; 146 } 147 148 149 bool SSynthFileReader::ReadSoundInRange(uint8& start, uint8& end, uint16& snd, uint32& size) { 150 size -= 4; 151 return Read(start) && Read(end) && Read(snd) && Skip(4); 152 } 153 154 155 bool SSynthFileReader::ReadSoundHeader(uint16& inst, BString& name, uint32& size) { 156 uint8 len; 157 return Skip(2) && Read(inst) && Read(len) && Read(name, len) && Read(size); 158 } 159 160 161 status_t SSynthFileReader::Initialize(SSynthFile* synth) { 162 uint32 version; 163 uint32 chunks; 164 uint32 nextChunk; 165 tag t; 166 167 if (ReadHeader(version, chunks, nextChunk)) { 168 for (uint32 chunk = 0; chunk < chunks; chunk ++) { 169 if (NextChunk(t, nextChunk)) { 170 if (TagEquals(t, "INST")) { 171 uint32 offset = Tell(); 172 uint16 inst; 173 uint16 snd; 174 uint16 snds; 175 BString name; 176 uint32 size; 177 if (ReadInstHeader(inst, snd, snds, name, size)) { 178 SInstrument* instr = synth->GetInstrument(inst); 179 instr->SetOffset(offset); 180 instr->SetName(name.String()); 181 instr->SetDefaultSound(synth->GetSound(snd)); 182 for (int s = 0; s < snds; s ++) { 183 uint8 start, end; 184 if (ReadSoundInRange(start, end, snd, size)) { 185 instr->Sounds()->AddItem(new SSoundInRange(start, end, synth->GetSound(snd))); 186 } else { 187 return B_ERROR; 188 } 189 } 190 } else { 191 return B_ERROR; 192 } 193 } else if (TagEquals(t, "snd ")) { 194 uint32 offset = Tell(); 195 uint16 inst; 196 BString name; 197 uint32 size; 198 if (ReadSoundHeader(inst, name, size)) { 199 SSound* s = synth->GetSound(inst); 200 s->SetOffset(offset); 201 s->SetName(name.String()); 202 } else { 203 return B_ERROR; 204 } 205 } else { 206 // skip 207 } 208 } else { 209 return B_ERROR; 210 } 211 } 212 return B_OK; 213 } 214 return B_ERROR; 215 } 216 217 // debugging 218 void SSynthFileReader::Print(tag tag) { 219 printf("%.*s", 4, tag); 220 } 221 222 223 void SSynthFileReader::Dump(uint32 bytes) { 224 uint8 byte; 225 int col = 0; 226 const int cols = 16; 227 bool first = true; 228 long start = ftell(fFile); 229 230 for (;bytes > 0 && Read(byte); bytes --, col = (col + 1) % cols) { 231 if (col == 0) { 232 if (first) first = false; 233 else printf("\n"); 234 printf("%6.6lx(%3.3lx) ", ftell(fFile)-1, ftell(fFile)-start-1); 235 } 236 printf("%2.2x ", (uint)byte); 237 if (isprint(byte)) printf("'%c' ", (char)byte); 238 else printf(" "); 239 } 240 } 241 242 void SSynthFileReader::Dump(bool play, uint32 instrOnly) { 243 tag tag; 244 uint32 version; 245 uint32 nEntries; 246 uint32 next; 247 uint32 cur; 248 249 printf("SynthFileReader::Dump\n"); 250 printf("=================\n\n"); 251 252 // read header 253 fseek(fFile, 0, SEEK_SET); 254 Read(tag); ASSERT(TagEquals(tag, "IREZ")); 255 if (Read(version) && Read(nEntries)) { 256 printf("version= %ld entries= %ld\n", version, nEntries); 257 258 // dump rest of file 259 // for (uint32 i = 0; i < nEntries; i++) { 260 while (Read(next)) { 261 printf("next=%lx cur=%lx ", next, cur); 262 cur = ftell(fFile); 263 if (Read(tag)) { 264 Print(tag); 265 if (!play && TagEquals(tag, "INST")) { 266 uint32 inst; 267 uint8 len; 268 BString name; 269 uint32 size; 270 271 if (Read(inst) && Read(len) && Read(name, len) && Read(size)) { 272 uint32 rest = size; 273 printf(" inst=%d '%s' size=%lx", (int)inst, name.String(), size); 274 275 printf("\n"); Dump(12); printf("\n"); 276 rest -= 10; 277 278 uint16 elems; 279 Read(elems); 280 rest -= 4; 281 282 printf("elems = %d\n", elems); 283 284 if (elems > 0 || rest >= 16) { 285 Dump(elems * 8 + 21); printf("\n"); 286 287 rest -= elems * 8 + 21; 288 } else { 289 printf("rest %ld\n", rest); 290 Dump(rest); 291 rest = 0; 292 } 293 294 bool prev_was_sust = false; 295 while (rest > 0) { 296 Read(tag); rest -= 4; 297 Print(tag); printf("\n"); 298 int s = 0; 299 if (TagEquals(tag, "ADSR")) { 300 s = 1+4+4; 301 } else if (TagEquals(tag, "LINE")) { 302 s = 8; 303 } else if (TagEquals(tag, "SUST")) { 304 s = 8; 305 } else if (TagEquals(tag, "LAST")) { 306 s = 0; 307 if (rest > 0) { 308 SSynthFileReader::tag tag2; 309 long pos = ftell(fFile); 310 Read(tag2); 311 fseek(fFile, pos, SEEK_SET); 312 if (!isalpha(tag2[0])) { 313 s = 4; 314 } 315 } 316 } else if (TagEquals(tag, "LPGF")) { 317 s = 12; 318 } else if (TagEquals(tag, "LPFR")) { 319 s = 9; 320 } else if (TagEquals(tag, "SINE")) { 321 s = 8; 322 } else if (TagEquals(tag, "LPRE")) { 323 s = 9; 324 } else if (TagEquals(tag, "PITC")) { 325 s = 9; 326 } else if (TagEquals(tag, "LPAM")) { 327 s = 9; 328 } else if (TagEquals(tag, "VOLU")) { 329 s = 9; 330 } else if (TagEquals(tag, "SPAN")) { 331 s = 9; 332 } else if (TagEquals(tag, "TRIA")) { 333 s = 8; 334 } else if (TagEquals(tag, "SQU2")) { 335 s = 8; 336 } else if (TagEquals(tag, "SQUA")) { 337 s = 8; 338 // Patches*.hsb 339 } else if (TagEquals(tag, "CURV")) { 340 s = 0; 341 } else { 342 // ASSERT(false); 343 printf("unknown tag "); Print(tag); printf("\n"); 344 // ASSERT(false); 345 break; 346 } 347 prev_was_sust = TagEquals(tag, "SUST"); 348 Dump(s); printf("\n"); 349 if (rest < s) { 350 printf("wrong size: rest=%ld size= %d\n", rest, s); 351 break; 352 } 353 rest -= s; 354 } 355 if (rest > 0) { 356 printf("Rest:\n"); 357 Dump(rest); printf("\n"); 358 } 359 } 360 } else if (TagEquals(tag, "snd ")) { 361 uint32 inst; 362 uint8 len; 363 BString name; 364 uint32 size; 365 366 if (Read(inst) && Read(len) && Read(name, len) && Read(size)) { 367 printf(" inst=%lx '%s' size=%lx\n", inst, name.String(), size); 368 uint32 rest = size; 369 Dump(28); printf("\n"); rest -= 28; 370 uint16 rate; 371 Read(rate); rest -= 2; 372 printf("rate=%d\n", (int)rate); 373 Dump(16*3+7); printf("\n"); rest -= 16*3+7; 374 printf("size=%ld offsetToNext=%ld\n", size, next-cur); 375 if (play && (instrOnly==0xffff || instrOnly == inst)) Play(rate, 0, rest); 376 } 377 } 378 printf("\n"); 379 } else { 380 exit(-1); 381 } 382 fseek(fFile, next, SEEK_SET); 383 } 384 } else { 385 printf("Could not read header\n"); 386 } 387 } 388 389 #include <GameSoundDefs.h> 390 #include <SimpleGameSound.h> 391 392 void SSynthFileReader::Play(uint16 rate, uint32 offset, uint32 size) { 393 uint8* samples = new uint8[size]; 394 fseek(fFile, offset, SEEK_CUR); 395 Read((void*)samples, size); 396 397 BSimpleGameSound* s; 398 gs_audio_format format = { 399 rate, 400 1, 401 gs_audio_format::B_GS_S16, 402 2, 403 0 404 }; 405 s = new BSimpleGameSound((void*)samples, size/2, &format); 406 if (s->InitCheck() == B_OK) { 407 s->StartPlaying(); 408 s->SetIsLooping(true); 409 printf("hit enter "); while (getchar() != '\n'); 410 s->StopPlaying(); 411 } else { 412 printf("Could not initialize BSimpleGameSound!\n"); 413 } 414 delete s; 415 } 416