void ConvertSong(byte[] srcdata, SongSt srcsong, byte[] destdata, SongSt destsong) { InstrumentMap instrument_map = new InstrumentMap(srcdata, srcsong.voices); List <List <byte> > trackdata = new List <List <byte> >(); if (instrument_map.ErrorMessage != "") { DialogResult dr = R.ShowNoYes("この曲のデータ構造は壊れているようです。\r\nインポートを強行しますか?\r\n強行する場合は、正しく認識できたトラックのみをインポートします。" + "\r\n\r\n" + instrument_map.ErrorMessage); if (dr != System.Windows.Forms.DialogResult.Yes) { return; } } //曲の取出し. this.ErrorMessage = ""; bool success = Rip(srcdata, srcsong, instrument_map, trackdata); if (success == false) { R.ShowStopError("この曲のデータ構造は壊れているため、Rip出来ませんでした。" + "\r\n\r\n" + this.ErrorMessage); return; } //取り出した曲を書き込む. Burn(destsong, instrument_map, trackdata); }
private static RootElement ConvertRootElement(KeySwitch source, ListElement listOfPSoundSlot, ListElement listOfUSlotVisuals) { // Construction of InstrumentMap element var slots = InstrumentMap.Slots(listOfPSoundSlot); var slotVisuals = InstrumentMap.SlotVisuals(listOfUSlotVisuals); var instrumentName = $"{source.ProductName.Value} {source.InstrumentName.Value}"; var rootElement = InstrumentMap.New(instrumentName); rootElement.Member.Add(slotVisuals); rootElement.Member.Add(slots); rootElement.StringElement.Value = instrumentName; return(rootElement); }
bool Rip(byte[] data, SongSt song, InstrumentMap instrument_map, List <List <byte> > trackdata) { //Rip for (uint track = 0; track < song.tracks; track++) { uint songtrack_pointer = song.header + 8 + (4 * track); uint songtrackdata_pointer = U.u32(data, songtrack_pointer); if (!U.isPointer(songtrackdata_pointer)) { this.ErrorMessage += "\r\n" + R.Error("track:" + track.ToString() + " can not pointer! addr:" + songtrack_pointer.ToString("X08") + " data:" + songtrackdata_pointer.ToString("X08")); return(false); } songtrackdata_pointer = U.toOffset(songtrackdata_pointer); List <byte> track_data = process_track(data, songtrackdata_pointer, instrument_map); trackdata.Add(track_data); } //ドラムがない曲の場合、それは困るので、ダミーのドラムを追加する. instrument_map.appendDrumIfNoDrum(); return(true); }
List <byte> process_track(byte[] data, uint songtrackdata_pointer, InstrumentMap instrument_map) { List <byte> ret = new List <byte>(); //Transform the data. uint position = songtrackdata_pointer; uint percussion = 0; while (true) { uint b = U.u8(data, position); position++; ret.Add((byte)b); if (b == 0xB1) { break; } else if (b == 0xB2 || b == 0xB3) { //repointer U.append_u32(ret, U.p32(data, position) - songtrackdata_pointer); position += 4; } else if (b == 0xBD) { uint next_byte = U.u8(data, position); position++; uint translated = instrument_map.translate(next_byte); if (translated == 0) { percussion = next_byte; } ret.Add((byte)translated); } else if (b == 0xBB || b == 0xBC || b == 0xBE || b == 0xBF || b == 0xC0 || b == 0xC1 || b == 0xC2 || b == 0xC3 || b == 0xC4 || b == 0xC5 || b == 0xC8) { // These commands take a data byte that must not be processed. ret.Add((byte)U.u8(data, position)); position++; } else if (b == 0xb9) {//MEMACC 4バイト命令 //最初の1バイトはコピー済みなので、残りの3バイトコピーする. ret.Add((byte)U.u8(data, position)); position++; ret.Add((byte)U.u8(data, position)); position++; ret.Add((byte)U.u8(data, position)); position++; } else if (percussion != 0 && b < 0x80) { uint inst = instrument_map.translate_percussion(percussion, b); ret[ret.Count - 1] = ((byte)inst); //There might be a volume marker, and then a 'gate' byte //For now, assuming that any subsequent low-value bytes are extra data //that should be passed as-is - even though previous experimentation suggested //that these bytes could be used to specify a chord... while (U.u8(data, position) < 0x80) {// Volume marker ret.Add((byte)U.u8(data, position)); position++; } } } return(ret); }
void Burn(SongSt song, InstrumentMap instrument_map, List <List <byte> > trackdata) { //必要なサイズを計算する. uint use_size = 8 + (4 * (uint)trackdata.Count); //ヘッダー for (int track = 0; track < trackdata.Count; track++) { use_size += (uint)trackdata[track].Count; //楽譜 } use_size = U.Padding4(use_size); //楽譜と楽器の間は 4バイトアライメントが必要. use_size += (uint)(instrument_map.Instrument_mapping.Count * 12); //楽器 use_size += (uint)instrument_map.Sample_data.Count; //楽器データ uint write_pointer = InputFormRef.AllocBinaryData(use_size); if (write_pointer == U.NOT_FOUND) { R.ShowStopError("データサイズを({0})確保できません。\r\nROM容量がもうないか、音楽のパースに失敗しています。", use_size); return; } U.toPointer(write_pointer); byte[] data = new byte[use_size]; U.write_u8(data, 0, (uint)trackdata.Count); //トラック数 U.write_u8(data, 1, 0x0); //常にゼロ. U.write_u8(data, 2, 0x0A); //Do these values matter? U.write_u8(data, 3, 0x80); //This is just copying what the stock ROM does... uint offset = 8 + (4 * (uint)trackdata.Count); //データ構造 //ヘッダー //[track数] [0] [0x0A] [0x80] [楽器ポンタ] [楽譜1ポインタ] [楽譜2ポインタ].... [楽譜Nポインタ] // //実データ //[楽譜1データ]....... //[楽譜2データ]....... // //[楽器データ] //[楽器サンプルデータ] //楽譜 for (int track = 0; track < trackdata.Count; track++) { //楽譜ポインタの書き込み U.write_u32(data, 8 + (4 * (uint)track), U.toPointer(write_pointer + offset)); //楽譜データを書き込む. burn_track(data, offset, write_pointer, trackdata[track].ToArray()); offset += (uint)trackdata[track].Count; } offset = U.Padding4(offset); //楽譜と楽器の間は 4バイトアライメントが必要. //楽器ポインタ U.write_u32(data, 4, U.toPointer(write_pointer + offset)); uint instrument_start = offset; //楽器開始 uint instrumentdata_start = instrument_start + (12 * (uint)instrument_map.Instrument_mapping.Count); //楽器データ開始 Log.Debug("instrumentdata_start(", instrumentdata_start.ToString(), ") = instrument_start(", instrument_start.ToString(), ") + 12 * instrument_count(", instrument_map.Instrument_mapping.Count.ToString(), ")"); U.write_range(data, instrument_start, instrument_map.Instrument_codes.ToArray()); U.write_range(data, instrumentdata_start, instrument_map.Sample_data.ToArray()); //楽器 uint resyclesize = 0; for (int i = 0; i < instrument_map.Instrument_mapping.Count; i++) { uint this_instrument = instrument_start + (12 * (uint)i); Log.Debug("track:", i.ToString(), " ", data[this_instrument + 0].ToString()); uint instrumentCode = U.u8(data, this_instrument + 0); if (SongInstrumentForm.IsDirectSound(instrumentCode) || SongInstrumentForm.IsWaveMemory(instrumentCode)) { uint sample_data_start = U.u32(data, this_instrument + 4); sample_data_start += instrumentdata_start; if (sample_data_start < resyclesize) { Log.Error("BAD INSTRUMENT:", i.ToString(), (sample_data_start - instrumentdata_start).ToString(), sample_data_start.ToString(), resyclesize.ToString()); continue; } sample_data_start -= resyclesize; uint sample_data_len; if (SongInstrumentForm.IsWaveMemory(instrumentCode)) { sample_data_len = 16; } else { sample_data_len = U.u32(data, sample_data_start + 12); sample_data_len = U.Padding4(sample_data_len); } Log.Debug("d ", sample_data_start.ToString("X"), " ", sample_data_len.ToString()); uint found_address = U.Grep(Program.ROM.Data, U.subrange(data, sample_data_start, sample_data_start + sample_data_len), 100, 0, 4); if (found_address != U.NOT_FOUND) { Log.Debug("recycle ", sample_data_start.ToString("X"), " len ", sample_data_len.ToString(), " -> ", found_address.ToString("X")); //existing address in ROM. //recycle data = U.del(data, sample_data_start, sample_data_start + sample_data_len); U.write_u32(data, this_instrument + 4, U.toPointer(found_address)); resyclesize += sample_data_len; } else { //nothing to recycle, write the data. uint baseoffset = U.u32(data, this_instrument + 4); //相対アドレスが書いてあるので、それを求めに絶対値に変換する U.write_u32(data, this_instrument + 4 , U.toPointer((instrumentdata_start + write_pointer + baseoffset) - resyclesize)); } } else if (instrumentCode == 0x80) { //ドラム uint baseoffset = U.u32(data, this_instrument + 4); //相対アドレスが書いてあるので、それを求めに絶対値に変換する U.write_u32(data, this_instrument + 4 , U.toPointer(instrument_start + write_pointer + baseoffset)); } else if (instrumentCode == 0x40) { Log.Debug("MULTI TRACK!"); uint baseoffset = U.u32(data, this_instrument + 4); //相対アドレスが書いてあるので、それを求めに絶対値に変換する U.write_u32(data, this_instrument + 4 , U.toPointer(instrument_start + write_pointer + baseoffset)); baseoffset = U.u32(data, this_instrument + 8); //相対アドレスが書いてあるので、それを求めに絶対値に変換する U.write_u32(data, this_instrument + 8 , U.toPointer((instrumentdata_start + write_pointer + baseoffset) - resyclesize)); } } Log.Notify("resyclesize:", resyclesize.ToString(), U.To0xHexString(resyclesize)); string undo_name = ""; Undo.UndoData undodata = Program.Undo.NewUndoData(undo_name); undodata.list.Add(new Undo.UndoPostion(song.table, 8)); Program.ROM.write_u32(song.table, U.toPointer(write_pointer)); InputFormRef.WriteBinaryDataDirect(write_pointer, data, undodata); uint priority = GetSongPriority(trackdata.Count); Program.ROM.write_u32(song.table + 4, priority, undodata); Program.Undo.Push(undodata); }