Ticket #9131: compress_bs1_mac.patch
File compress_bs1_mac.patch, 9.9 KB (added by , 14 years ago) |
---|
-
compress.h
125 125 void extractAndEncodeVOC(const char *outName, Common::File &input, AudioFormat compMode); 126 126 void extractAndEncodeWAV(const char *outName, Common::File &input, AudioFormat compMode); 127 127 128 void encodeAIF(const char *inName, const char *outName, AudioFormat compMode); 129 128 130 void encodeAudio(const char *inname, bool rawInput, int rawSamplerate, const char *outname, AudioFormat compmode); 129 131 void encodeRaw(char *rawData, int length, int samplerate, const char *outname, AudioFormat compmode); 130 132 void setRawAudioType(bool isLittleEndian, bool isStereo, uint8 bitsPerSample); -
engines/sword1/compress_sword1.h
30 30 CompressSword1(const std::string &name = "compress_sword1"); 31 31 32 32 virtual void execute(); 33 34 virtual InspectionMatch inspectInput(const Common::Filename &filename); 33 35 34 36 bool _compSpeech; 35 37 bool _compMusic; … … 45 47 void compressSpeech(const Common::Filename *inpath, const Common::Filename *outpath); 46 48 void compressMusic(const Common::Filename *inpath, const Common::Filename *outpath); 47 49 void checkFilesExist(bool checkSpeech, bool checkMusic, const Common::Filename *inpath); 50 void guessEndianness(int16 *data, int16 length); 51 52 private: 53 bool _macVersion; 54 55 enum Endianness { BigEndian , LittleEndian , UnknownEndian } ; 56 Endianness _speechEndianness; 48 57 }; 49 58 50 59 #endif -
engines/sword1/compress_sword1.cpp
343 343 } 344 344 free(fBuf); 345 345 *returnSize = resSize * 2; 346 if (_speechEndianness == UnknownEndian) 347 guessEndianness(dstData, length); 346 348 return dstData; 347 349 } else { 348 350 free(fBuf); … … 352 354 } 353 355 } 354 356 357 void CompressSword1::guessEndianness(int16 *data, int16 length) { 358 // Compute average of difference between two consecutive samples for both the given 359 // data array and the byte swapped array. 360 double bs_diff_sum = 0., diff_sum = 0.; 361 if (length > 2000) 362 length = 2000; 363 364 int16 prev_bs_value = (int16)SWAP_16(*((uint16*)data)); 365 for (int16 i = 1 ; i < length ; ++i) { 366 diff_sum += data[i] > data[i-1] ? data[i] - data[i-1] : data[i-1] - data[i]; 367 int16 bs_value = (int16)SWAP_16(*((uint16*)(data + i))); 368 bs_diff_sum += bs_value > prev_bs_value ? bs_value - prev_bs_value : prev_bs_value - bs_value; 369 prev_bs_value = bs_value; 370 } 371 // Set the little/big endian flags 372 if (diff_sum < bs_diff_sum) 373 _speechEndianness = LittleEndian; 374 else 375 _speechEndianness = BigEndian; 376 setRawAudioType(_speechEndianness == LittleEndian, false, 16); 377 } 378 355 379 uint8 *CompressSword1::convertData(uint8 *rawData, uint32 rawSize, uint32 *resSize) { 356 380 uint8 *resBuf; 357 381 … … 441 465 int i; 442 466 char cluName[256], outName[256]; 443 467 444 setRawAudioType(true, false, 16); 468 if (_speechEndianness != UnknownEndian) 469 setRawAudioType(_speechEndianness == LittleEndian, false, 16); 445 470 446 471 for (i = 1; i <= 2; i++) { 447 472 // Updates the progress bar, add music files if we compress those too … … 491 516 // Update the progress bar, we add 2 if we compress speech to, for those files 492 517 updateProgress(i, TOTAL_TUNES +(_compSpeech? 2 : 0)); 493 518 494 sprintf(fNameIn, "%s/MUSIC/%s.WAV", inpath->getPath().c_str(), musicNames[i].fileName); 519 if (!_macVersion) 520 sprintf(fNameIn, "%s/MUSIC/%s.WAV", inpath->getPath().c_str(), musicNames[i].fileName); 521 else 522 sprintf(fNameIn, "%s/MUSIC/%s.AIF", inpath->getPath().c_str(), musicNames[i].fileName); 495 523 try { 496 524 Common::File inf(fNameIn, "rb"); 497 525 … … 510 538 } 511 539 512 540 print("encoding file (%3d/%d) %s -> %s\n", i + 1, TOTAL_TUNES, musicNames[i].fileName, fNameOut); 513 encodeAudio(fNameIn, false, -1, fNameOut, _format); 541 if (!_macVersion) 542 encodeAudio(fNameIn, false, -1, fNameOut, _format); 543 else 544 encodeAIF(fNameIn, fNameOut, _format); 514 545 } catch (Common::FileException& err) { 515 546 print(err.what()); 516 547 } … … 544 575 } 545 576 } 546 577 578 /* The PC Version uses LittleEndian speech files. 579 The Mac version can be either with little endian speech files or big endian speech files. 580 We detect if we have a PC or Mac version with the music files (WAV for PC and AIF for Mac). 581 If we have the Mac version or if we don't check the music files, an heuristic will be used 582 when first accessing the speech file to detect if it is little endian or big endian */ 583 547 584 if (checkMusic) { 548 585 for (i = 0; i < 20; i++) { /* Check the first 20 music files */ 586 // Check WAV file 549 587 sprintf(fileName, "%s/MUSIC/%s.WAV", inpath->getPath().c_str(), musicNames[i].fileName); 550 588 testFile = fopen(fileName, "rb"); 551 589 552 590 if (testFile) { 553 591 musicFound = true; 554 592 fclose(testFile); 593 break; 555 594 } 595 596 // Check AIF file 597 sprintf(fileName, "%s/MUSIC/%s.AIF", inpath->getPath().c_str(), musicNames[i].fileName); 598 testFile = fopen(fileName, "rb"); 599 600 if (testFile) { 601 musicFound = true; 602 _macVersion = true; 603 _speechEndianness = UnknownEndian; 604 fclose(testFile); 605 break; 606 } 556 607 } 557 608 558 609 if (!musicFound) { … … 562 613 print("If your OS is case-sensitive, make sure the filenames\n"); 563 614 print("and directorynames are all upper-case.\n"); 564 615 } 616 } else { 617 _speechEndianness = UnknownEndian; 565 618 } 566 619 567 620 if ((checkSpeech && (!speechFound)) || (checkMusic && (!musicFound))) { … … 569 622 } 570 623 } 571 624 625 InspectionMatch CompressSword1::inspectInput(const Common::Filename &filename) { 626 // Wildcard matching as implemented in Tools is too restrictive (e.g. it doesn't 627 // work with *.cl? or even *.cl*). 628 // This is the reason why this function is reimplemented there. 629 if ( 630 scumm_stricmp(filename.getExtension().c_str(), "clu") == 0 || 631 scumm_stricmp(filename.getExtension().c_str(), "clm") == 0 632 ) 633 return IMATCH_PERFECT; 634 return IMATCH_AWFUL; 635 } 636 572 637 CompressSword1::CompressSword1(const std::string &name) : CompressionTool(name, TOOLTYPE_COMPRESSION) { 573 638 _compSpeech = true; 574 639 _compMusic = true; 640 _macVersion = false; 641 _speechEndianness = LittleEndian; 575 642 576 643 _supportsProgressBar = true; 577 644 578 645 ToolInput input; 579 input.format = "*. clu";646 input.format = "*.*"; 580 647 _inputPaths.push_back(input); 581 648 582 649 _shorthelp = "Used to compress the Broken Sword 1 data files."; -
compress.cpp
26 26 #include <sstream> 27 27 #include <stdio.h> 28 28 29 29 #include "compress.h" 30 #include "common/endian.h" 30 31 31 32 #ifdef USE_VORBIS 32 33 #include <vorbis/vorbisenc.h> … … 593 594 encodeAudio(outName, false, -1, tempEncoded, compMode); 594 595 } 595 596 597 void CompressionTool::encodeAIF(const char *inName, const char *outName, AudioFormat compmode) { 598 // Get sound definition (length, frequency, stereo, ...) 599 char buf[4]; 600 Common::File inFile(inName, "rb"); 601 inFile.read_throwsOnError(buf, 4); 602 if (memcmp(buf, "FORM", 4) != 0) 603 error("Error: AIFF file has no 'FORM' header"); 604 inFile.readUint32BE(); 605 // Only AIFF (uncompressed) is supported, not AIFC 606 inFile.read_throwsOnError(buf, 4); 607 if (memcmp(buf, "AIFF", 4) != 0) 608 error("Error: AIFF file has no 'AIFF' header"); 609 610 bool foundCOMM = false; 611 bool foundSSND = false; 612 uint16 numChannels = 0, bitsPerSample = 0; 613 uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0; 614 uint32 sampleRate = 0; 615 616 while ((!foundCOMM || !foundSSND) && !inFile.err() && !inFile.eos()) { 617 618 inFile.read_throwsOnError(buf, 4); 619 uint32 length = inFile.readUint32BE(); 620 uint32 pos = inFile.pos(); 621 622 if (memcmp(buf, "COMM", 4) == 0) { 623 foundCOMM = true; 624 numChannels = inFile.readUint16BE(); 625 numSampleFrames = inFile.readUint32BE(); 626 bitsPerSample = inFile.readUint16BE(); 627 // The sample rate is stored as an "80 bit IEEE Standard 754 floating 628 // point number (Standard Apple Numeric Environment [SANE] data type 629 // Extended). 630 byte rate_buf[10]; 631 uint32 last = 0; 632 inFile.read_throwsOnError(rate_buf, 10); 633 sampleRate = READ_BE_UINT32(rate_buf + 2); 634 byte exp = 30 - rate_buf[1]; 635 636 while (exp--) { 637 last = sampleRate; 638 sampleRate >>= 1; 639 } 640 641 if (last & 0x00000001) 642 sampleRate++; 643 } else if (memcmp(buf, "SSND", 4) == 0) { 644 foundSSND = true; 645 offset = inFile.readUint32BE(); 646 blockSize = inFile.readUint32BE(); 647 soundOffset = inFile.pos(); 648 } 649 650 inFile.seek(pos + length, SEEK_SET); 651 } 652 if (!foundCOMM) 653 error("Error: AIFF file has no 'COMM' chunk in 'AIFF' header"); 654 655 if (!foundSSND) 656 error("Error: AIFF file has no 'COMM' chunk in 'SSND' header"); 657 658 // Only a subset of the AIFF format is supported 659 if (numChannels < 1 || numChannels > 2) 660 error("Error: AIFF file has an unsupported number of channels"); 661 662 if (bitsPerSample != 8 && bitsPerSample != 16) 663 error("Error: AIFF file has an unsupported number of bits per sample"); 664 665 if (offset != 0 || blockSize != 0) 666 error("Error: AIFF file has block-aligned data, which is not supported"); 667 668 // Get data and write to temporary file 669 uint32 size = numSampleFrames * numChannels * (bitsPerSample / 8); 670 inFile.seek(soundOffset, SEEK_SET); 671 char *aifData = (char *)malloc(size); 672 inFile.read_throwsOnError(aifData, size); 673 Common::File tmpFile(TEMP_RAW, "wb"); 674 tmpFile.write(aifData, size); 675 tmpFile.close(); 676 677 // Convert the temporary raw file to MP3/OGG/FLAC 678 // Samples are always signed, and big endian. 679 setRawAudioType(false, numChannels == 2, bitsPerSample); 680 encodeAudio(TEMP_RAW, true, sampleRate, outName, compmode); 681 682 // Delete temporary file 683 unlink(TEMP_RAW); 684 } 685 596 686 void CompressionTool::extractAndEncodeVOC(const char *outName, Common::File &input, AudioFormat compMode) { 597 687 int bits; 598 688 int blocktype;