public ITFHeader ToITF() { ITFHeader result = new ITFHeader(); result.BeatPerMinute = Header.DefaultBPM; result.TickPerRow = Header.DefaultTempo; foreach (var pat in Patterns) { ITFPattern itfp = new ITFPattern(); bool emptypattern = true; for (int row = 0; row < pat.NumberOfRows; row++) { ITFRow itfr = new ITFRow(); bool emptyrow = true; for (int channel = 0; channel < Header.NumberOfChannels; channel++) { XMNote xmnote = pat.PatArr[row, channel]; ITFNote itfn = null; if (xmnote != null) { emptyrow = false; emptypattern = false; itfn = new ITFNote(); if (xmnote.Instrument != 0) { itfn.Instrument = xmnote.Instrument; } if (xmnote.Note != 0) { itfn.Note = xmnote.Note; } itfn.Volume = xmnote.Volume; itfn.NoteOff = xmnote.noteoff; itfn.Effect = xmnote.Effect; itfn.EffectParam = xmnote.EffectParam; } itfr.Channels.Add(itfn); } if (emptyrow) { itfr = null; } itfp.Rows.Add(itfr); } if (emptypattern) { itfp = null; } result.Patterns.Add(itfp); } foreach (byte item in Header.PatternOrderTable) { result.PlayOrder.Add(result.Patterns[item]); } return(result); }
public static List <byte> PatternToBytes(this ITFPattern itfpattern, Conversion conv, bool[] channelson = null, int?FromRow = null, int?ToRow = null) { int usedchannels = Math.Min(itfpattern.Rows.Max(x => x.Channels.Count), 8); if (channelson == null) { channelson = new bool[usedchannels]; for (int i = 0; i < channelson.Length; i++) { channelson[i] = true; } } List <byte> bytes = new List <byte>(); byte register, value = 0; for (int rows = 0; rows < itfpattern.Rows.Count; rows++) { if (FromRow.HasValue && FromRow.Value > rows) { continue; } if (ToRow.HasValue && ToRow.Value < rows) { continue; } //Is there any effects needs ticking here? bool tickingneeded = false; for (int channels = 0; channels < itfpattern.Rows[rows].Channels.Count; channels++) { ITFNote cn = itfpattern.Rows[rows].Channels[channels]; //Tempo determination. This can come from all available channels. if (cn.Effect == 0xF) { if (cn.EffectParam < 32) { conv.CurrentTickPerRow = cn.EffectParam.Value; } else { conv.CurrentBPM = cn.EffectParam.Value; } } //Ticking will apply only for the phisycally converted channels. if (channels > usedchannels) { continue; } int epu = ((byte)cn.EffectParam.Value >> 4) & 0xF; int epd = (byte)cn.EffectParam.Value & 0xF; tickingneeded = tickingneeded || (cn.Effect == 0xE && epu == 0xD) || (cn.Effect == 0xE && epu == 0xC) || (cn.Effect == 0xA && cn.EffectParam != 0); } if (tickingneeded) { ITFNote[,] tickarr = new ITFNote[conv.CurrentTickPerRow, usedchannels]; for (int channel = 0; channel < usedchannels; channel++) { if (!channelson[channel]) { continue; } ITFNote cn = itfpattern.Rows[rows].Channels[channel]; int epu = ((byte)cn.EffectParam.Value >> 4) & 0xF; int epd = (byte)cn.EffectParam.Value & 0xF; if (cn.Effect == 0xA && cn.EffectParam != 0) //Volume slide { tickarr[0, channel] = cn; int volume = cn.Volume.Value; int diff = -epd; if (epu != 0) { diff = epu; } for (int i = 1; i < conv.CurrentTickPerRow; i++) { volume += diff; if (volume < 0) { volume = 0; } if (volume > 64) { volume = 64; } tickarr[i, channel] = new ITFNote() { Volume = (byte)volume }; } } else if (cn.Effect == 0xE && epu == 0xD) { if (epd > 5) { epd = 5; } tickarr[epd, channel] = cn; } else if (cn.Effect == 0xE && epu == 0xC) //Note cut { if (epd > 5) { epd = 5; } tickarr[0, channel] = cn; tickarr[epd, channel] = new ITFNote() { NoteOff = true }; } else { tickarr[0, channel] = cn; } } for (int ticks = 0; ticks < conv.CurrentTickPerRow; ticks++) { for (int channel = 0; channel < usedchannels; channel++) { if (!channelson[channel]) { continue; } ITFNote cn = tickarr[ticks, channel]; if (cn != null) { NoteIntoBytes(cn, bytes, channel, conv); } } //Timing register = 0; value = (byte)bpmtoplayertick(conv); addtobytes(bytes, register, value, conv.CYMS); } } else { for (int channel = 0; channel < usedchannels; channel++) { if (!channelson[channel]) { continue; } ITFNote cn = itfpattern.Rows[rows].Channels[channel]; NoteIntoBytes(cn, bytes, channel, conv); } //Timing register = 0; value = (byte)bpmtoplayertickrow(conv); addtobytes(bytes, register, value, conv.CYMS); } } return(bytes); }