public byte[] GetRawSongs() { if (this.id == 0) { var dataLength = 0; //get data length, for faster concat for (int i = 0; i < songList.Count; i++) { dataLength += songList[i].rawData.Length; } byte[] midiData = new byte[dataLength]; int index = 0; //do fast concat for (int i = 0; i < songList.Count; i++) { var songRawData = CGeneric.GiveMeArray(songList[i].rawData, 0, songList[i].rawData.Length); for (int j = 0; j < songList[i].rawData.Length; j++) { midiData[index + j] = songRawData[j]; } index += songList[i].rawData.Length; } return(midiData); } else { return(midi); } }
private void DecomposeSounds() { nbInstruments = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, 0x20, 4)); int indexSoundPtr = 0; int soundLength = 0; for (int i = 0; i < nbInstruments; i++) { Sound sound = new Sound(); sound.start = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, indexSoundPtr + 0x30, 4)); soundLength = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, indexSoundPtr + 0x34, 4)); //grab sound data sound.rawData = CGeneric.GiveMeArray(waveTable, sound.start, soundLength); sound.loop.offset = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, indexSoundPtr + 0x3C, 4)); sound.predictor.offset = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, indexSoundPtr + 0x40, 4)); //loop if (sound.loop.offset != 0) { sound.loop.start = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, sound.loop.offset, 4)); sound.loop.end = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, sound.loop.offset + 4, 4)); sound.loop.count = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, sound.loop.offset + 8, 4)); sound.loop.state = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, sound.loop.offset + 0xC, 0x20)); } //predictors sound.predictor.order = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, sound.predictor.offset, 4)); sound.predictor.nPredictors = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(ptrTable, sound.predictor.offset + 4, 4)); sound.predictor.predictors = CGeneric.GiveMeArray(ptrTable, sound.predictor.offset + 8, sound.predictor.order * sound.predictor.nPredictors * 8 * 2); sound.predictor.predictorShort = new short[sound.predictor.predictors.Length / 2]; for (int j = 0; j < sound.predictor.predictorShort.Length; j++) { sound.predictor.predictorShort[j] = BitConverter.ToInt16(new[] { sound.predictor.predictors[j * 2 + 1], sound.predictor.predictors[j * 2] }, 0); } if (sound.loop.offset != 0) { indexSoundPtr = sound.loop.offset; } else { indexSoundPtr += 0xA0; } soundList.Add(sound); } }
/// <summary> /// /// </summary> /// <param name="wavData">the waveData</param> /// <param name="predictorOrder"></param> /// <param name="predictors"></param> /// <param name="npredictors"></param> /// <returns></returns> public static short[] Decode(byte[] wavData, int predictorOrder, short[] predictors, int npredictors) { int index; int pred; short[] output = new short[wavData.Length * 2]; short[] tmpOut = new short[8]; //flip the predictors short[] preds = new short[32 * npredictors]; for (int j = 0; j < (8 * predictorOrder * npredictors); j++) { preds[j] = predictors[j]; } int indexIn = 0; int indexOut = 0; int i = (wavData.Length / 9) * 9; while (i > 0) { index = (wavData[indexIn] >> 4) & 0xF; pred = (wavData[indexIn] & 0xF); i--; short[] pred1 = new short[16]; for (int j = 0; j < 16; j++) { pred1[j] = preds[pred * 16 + j]; } indexIn++; tmpOut = Decode8(CGeneric.GiveMeArray(wavData, indexIn, 8), index, pred1, tmpOut, pred); Array.Copy(tmpOut, 0, output, indexOut, 8); indexIn += 4; i -= 4; indexOut += 8; tmpOut = Decode8(CGeneric.GiveMeArray(wavData, indexIn, i == 4 ? i:8), index, pred1, tmpOut, pred); Array.Copy(tmpOut, 0, output, indexOut, 8); indexIn += 4; i -= 4; indexOut += 8; } //trim 00 end padding return(output.Take(indexOut).ToArray()); }
private byte[] DecodeSound() { var shortArray = AudioDecode.Decode(rawData, predictor.order, predictor.predictorShort, predictor.nPredictors); byte[] byteArray = new byte[shortArray.Length * 2]; byte[] tmp = new byte[2]; for (int i = 0; i < shortArray.Length; i++) { tmp = CGeneric.ConvertIntToByteArray16bits(shortArray[i]); byteArray[i * 2] = tmp[1]; byteArray[i * 2 + 1] = tmp[0]; } return(byteArray); }
private int DecomposeSong() { int songTotalLength = 0; for (int i = 0; i < songDataAddress.Length; i += 8) { //starting address song0 int songAddress = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(songDataAddress, i, 4)); int songLength = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(songDataAddress, i + 4, 4)) - songAddress; //grab the start address of song byte[] songRawData = CGeneric.GiveMeArray(rawData, songAddress - positionPtrStart, songLength); Song song = new Song(songRawData); songList.Add(song); songTotalLength += songLength; } return(songTotalLength); }
private byte[] GetWavHeader(int soundBank, int instrument, int lengthWave) { byte[] wavHeader = CGeneric.patternHeaderWavFile; int loopHeader = 0; if (loop.count > 0) { loopHeader = 0x18; } byte[] fileSize = CGeneric.ConvertIntToByteArray(0x4C + lengthWave + loopHeader); wavHeader[0x04] = fileSize[3]; wavHeader[0x05] = fileSize[2]; wavHeader[0x06] = fileSize[1]; wavHeader[0x07] = fileSize[0]; if (IsHalfSamplingRate(soundBank, instrument)) { wavHeader[0x18] = 0x11; wavHeader[0x19] = 0x2B; wavHeader[0x1C] = 0x22; wavHeader[0x1D] = 0x56; } else { wavHeader[0x18] = 0x22; wavHeader[0x19] = 0x56; wavHeader[0x1C] = 0x44; wavHeader[0x1D] = 0xAC; } byte[] lengthFile = CGeneric.ConvertIntToByteArray(lengthWave); wavHeader[0x28] = lengthFile[3]; wavHeader[0x29] = lengthFile[2]; wavHeader[0x2A] = lengthFile[1]; wavHeader[0x2B] = lengthFile[0]; return(wavHeader); }
private byte[] GetWavBottom() { byte[] wavBottom = CGeneric.patternBottomWavFile; if (loop.count > 0) { wavBottom[0x4] = 0x3C; wavBottom[0x24] = 0x01; var loopStartByte = CGeneric.ConvertIntToByteArray(loop.start); var loopEndByte = CGeneric.ConvertIntToByteArray(loop.end); wavBottom[0x34] = loopStartByte[3]; wavBottom[0x35] = loopStartByte[2]; wavBottom[0x36] = loopStartByte[1]; wavBottom[0x37] = loopStartByte[0]; wavBottom[0x38] = loopEndByte[3]; wavBottom[0x39] = loopEndByte[2]; wavBottom[0x3A] = loopEndByte[1]; wavBottom[0x3B] = loopEndByte[0]; if (loop.count != -1) { var loopCountByte = CGeneric.ConvertIntToByteArray(loop.count); wavBottom[0x40] = loopCountByte[3]; wavBottom[0x41] = loopCountByte[2]; wavBottom[0x42] = loopCountByte[1]; wavBottom[0x43] = loopCountByte[0]; } } else { wavBottom[0x4] = 0x24; } //keybase to add wavBottom[0x14] = 0x3C; return(wavBottom); }
//search for N64 PtrTable V2 for cutting soundbank private void ChunkSoundBank() { byte[] tmpRawDataN64PtrTable = new byte[16]; //initialized to 16 to avoid first soundbank set to 0.. int sizeOfSoundBank = 16; //searching N64PtrTableV2 pattern (each one will be stored in a soundbank) int position = initialIndexAudioStart; int positionNext = 0; for (int i = 0; i <= 0x15; i++) { positionNext = CGeneric.SearchBytesInArray(rawData, CGeneric.patternN64PtrTableV2, 0, position + 16, 16); //if it's the last, don't search the next, just search the end of the rom if (positionNext == -1) { positionNext = CGeneric.SearchBytesInArray(rawData, CGeneric.endOfRom, 0, position + 16, 16); } sizeOfSoundBank = positionNext - position; if (i == 0)//for the first soundBank, give { byte[] startingEndingAddress = CGeneric.GiveMeArray(rawData, RomLangAddress.GetMidiSongSoundBank0(), 0x238); soundBankList.Add(new SoundBank(CGeneric.GiveMeArray(rawData, position, sizeOfSoundBank), soundBankList.Count, position, startingEndingAddress)); } else { soundBankList.Add(new SoundBank(CGeneric.GiveMeArray(rawData, position, sizeOfSoundBank), soundBankList.Count)); } position += sizeOfSoundBank; sizeOfSoundBank = 16; } }
public void WriteAllData(FileStream fs) { //set 16bit alignment for first soundbank int alignment = 16 - ((int)fs.Position % 16); for (int i = 0; i < alignment; i++) { fs.WriteByte(0); } //update address of midi (SoundBank 0) by making the difference between old position and new position this.finalIndexAudioStart = (int)fs.Position; //Array.Copy(rawData, RomLangAddress.GetMidiSongSoundBank0(), addressHeaderSb0, 0, addressHeaderSb0.Length); //set the good position of song, and write to rom int valueToStore1 = 0; int lengthData = 0; int adder = 0; fs.Position = RomLangAddress.GetMidiSongSoundBank0(); for (int i = 0; i < soundBankList[0].songList.Count; i++) { //finalindexaudiostart + ptrlength+wavedatalength valueToStore1 = finalIndexAudioStart + soundBankList[0].ptrTable.Length + soundBankList[0].waveTable.Length + adder; lengthData = soundBankList[0].songList[i].rawData.Length; fs.Write(CGeneric.ConvertIntToByteArray(valueToStore1), 0, 4); fs.Write(CGeneric.ConvertIntToByteArray(valueToStore1 + lengthData), 0, 4); adder += lengthData; } /*for (int i = 0; i < addressHeaderSb0.Length; i += 4) * { * int tmpValue = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(addressHeaderSb0, i, 4)); * if (finalIndexAudioStart > initialIndexAudioStart) * tmpValue += finalIndexAudioStart - initialIndexAudioStart; * else * tmpValue -= initialIndexAudioStart - finalIndexAudioStart; * byte[] tmpBytesNew = CGeneric.ConvertIntToByteArray(tmpValue); * for(int j = 0; j < tmpBytesNew.Length; j++) * addressHeaderSb0[i + j] = tmpBytesNew[j]; * * }*/ //write rawData soundBank fs.Position = finalIndexAudioStart; //write ptrData, waveTable, midi and sfx for (int i = 0; i <= 0x15; i++) { //write ptrData and update position soundBankList[i].address.PtrTable = CGeneric.ConvertIntToByteArray((int)fs.Position); fs.Write(soundBankList[i].ptrTable, 0, soundBankList[i].ptrTable.Length); //write waveTable and update position soundBankList[i].address.WaveTable = CGeneric.ConvertIntToByteArray((int)fs.Position); fs.Write(soundBankList[i].waveTable, 0, soundBankList[i].waveTable.Length); //write midi song and update sfx position ! (will only change the position of soundbank 1 and 2, the others doesn't have midi) soundBankList[i].address.Sfx = CGeneric.ConvertIntToByteArray((int)fs.Position); fs.Write(soundBankList[i].GetRawSongs() /*midi*/, 0, soundBankList[i].GetRawSongs().Length /*midi.Length*/); //write sfx and update position fs.Write(soundBankList[i].sfx, 0, soundBankList[i].sfx.Length); //write end position soundBankList[i].address.end = CGeneric.ConvertIntToByteArray((int)fs.Position); } long savedFsPosition = fs.Position; //update address in the header (first part) for (int i = 0; i <= 0x15; i++) { fs.Position = RomLangAddress.GetSoundBankPtrTable()[i]; fs.Write(soundBankList[i].address.PtrTable, 0, 4); fs.Write(soundBankList[i].address.WaveTable, 0, 4); if (i == 0 || i == 2) { if (i == 2) { fs.Position -= 0x38; fs.Write(soundBankList[i].address.Sfx, 0, 4); // in fact, it's the start of midi fs.Write(soundBankList[i].address.end, 0, 4); // and it's end here (and not the sfx) fs.Position += 0x30; } byte[] nullBytes = new byte[4]; fs.Write(nullBytes, 0, 4); fs.Write(nullBytes, 0, 4); } else { fs.Write(soundBankList[i].address.Sfx, 0, 4); //small hack.. weird part in the rom... if (i != 1) { fs.Write(soundBankList[i].address.end, 0, 4); } else { int oldValue = CGeneric.ConvertByteArrayToInt(soundBankList[i].address.end); byte[] newValue = CGeneric.ConvertIntToByteArray(oldValue - 0x470); fs.Write(newValue, 0, 4); } } fs.Write(soundBankList[i].address.WaveTable, 0, 4); } //update address in the header(second part) for (int i = 4; i <= 0x14; i++) { fs.Position = RomLangAddress.GetSoundBankPtrTable()[i] + 0x168; fs.Write(soundBankList[i].address.PtrTable, 0, 4); fs.Write(soundBankList[i].address.WaveTable, 0, 4); fs.Write(soundBankList[i].address.Sfx, 0, 4); fs.Write(soundBankList[i].address.end, 0, 4); fs.Write(soundBankList[i].address.WaveTable, 0, 4); } fs.Position = savedFsPosition; }
//chunk RawData into PtrTable, WaveTable and Sfx private void ChunkRawData(int id) { //initialized to 16 to avoid first soundbank set to 0.. int sizeOfPtrTable = 0; //searching waveTable (end of PtrTable) and write ptrTable rawData sizeOfPtrTable = CGeneric.SearchBytesInArray(rawData, CGeneric.patternN64WaveTable, 0, 16, 16); ptrTable = CGeneric.GiveMeArray(rawData, 0, sizeOfPtrTable); //waveTable = CGeneric.GiveMeArray(rawData,ptrTable.Length,rawData.Length - ptrTable.Length); int sizeSfx = 0; int sizeMidi = 0; //searching midi and sfx switch (id) { case 0: sizeMidi = DecomposeSong(); break; //there is a midi song and sfx, so with a unknow wavetable length, we need to determine sfx and midi length.. case 1: var startMidi = CGeneric.SearchBytesInArray(rawData, CGeneric.patternMidiSoundBank1, 0, 0, 16); sizeMidi = RomLangAddress.GetSizeMidiSoundBank1(); sizeSfx = rawData.Length - (startMidi + sizeMidi); break; //there is song but no sfx case 2: sizeMidi = RomLangAddress.GetSizeMidiSoundBank2(); break; //standard computed sfx size and no midi file (dirty check, but seems working pretty well). default: int tmpSfxEqualValue; int tmpSfxEqualValue2; int tmpSfxEqualValue3; int tmpSfxNull; for (int i = ptrTable.Length; i < rawData.Length - 16; i += 16) { //quick test, for avoiding cpu consuption tmpSfxNull = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(rawData, i + 12, 4)); if (tmpSfxNull == 0) { tmpSfxEqualValue = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(rawData, i, 4)); tmpSfxEqualValue2 = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(rawData, i + 4, 4)); tmpSfxEqualValue3 = CGeneric.ConvertByteArrayToInt(CGeneric.GiveMeArray(rawData, i + 8, 4)); var tmpSfxEqualValue4 = tmpSfxEqualValue3++; if (tmpSfxEqualValue != 0 && tmpSfxEqualValue == tmpSfxEqualValue2 && (tmpSfxEqualValue2 == tmpSfxEqualValue4 || tmpSfxEqualValue2 == tmpSfxEqualValue3)) { sizeSfx = rawData.Length - i; break; } } } break; } //store date with size found previously waveTable = CGeneric.GiveMeArray(rawData, ptrTable.Length, rawData.Length - (ptrTable.Length + sizeMidi + sizeSfx)); midi = CGeneric.GiveMeArray(rawData, ptrTable.Length + waveTable.Length, sizeMidi); sfx = CGeneric.GiveMeArray(rawData, ptrTable.Length + waveTable.Length + sizeMidi, sizeSfx); }