public ChannelNote() { octave = int.MinValue; note = char.MinValue; seminote = char.MinValue; instrument = string.Empty; envData = new EnvelopeData(); }
public static bool Compare(EnvelopeData e1, EnvelopeData e2) { return((null == e1 && null == e2) || ((null != e1 && null != e2) && (e1.ActiveFrequencies == e2.ActiveFrequencies) && (e1.FrequencyRatio == e2.FrequencyRatio) && (e1.Style == e2.Style))); }
public static bool Compare(EnvelopeData e1, EnvelopeData e2) { return (null == e1 && null == e2) || ((null != e1 && null != e2) && (e1.ActiveFrequencies == e2.ActiveFrequencies) && (e1.FrequencyRatio == e2.FrequencyRatio) && (e1.Style == e2.Style)); }
public ChannelNote() { octave = int.MinValue; note = char.MinValue; seminote = char.MinValue; instrument = string.Empty; envData = new EnvelopeData(); }
public void CopyFrom(ChannelNote newValues) { this.octave = newValues.octave; this.note = newValues.note; this.seminote = newValues.seminote; this.instrument = newValues.instrument; this.envData = newValues.EnvData.Clone(); this.volModifier = newValues.volModifier; }
private ApplicationState() { BaseOctave = 3; Stereo = LibAYEmu.Stereo.Mono; CurrentEnvData = new EnvelopeData(); }
private ApplicationState() { BaseOctave = 3; Stereo = LibAYEmu.Stereo.Mono; CurrentEnvData = new EnvelopeData(); }
public static byte[] GenerateSong(Song song) { List<byte> bytes = new List<byte>(); Pattern current; ChannelNote note; int noteLen; bool lastNoteSilence; string[] lastInstrument = new string[song.Channels]; EnvelopeData[] lastEnvelopes = new EnvelopeData[song.Channels]; int[] loopLocations = new int[song.Channels + 1]; int d; int dSeminote; int o; bytes.Add(song.Tempo); byte headerByte = (byte)(song.Looped ? 0x01 : 0x00); headerByte |= (byte)((song.FxChannel & 0x7) << 1); headerByte |= (byte)((song.Channels & 0x7) << 4); bytes.Add(headerByte); // Dos bytes reservados (de momento). bytes.Add(0); bytes.Add(0); // Metemos los bytes de offset de loops. int offsetLoopLocations = bytes.Count; bytes.AddRange(new byte[2 * (song.Channels + 1)]); for (int currentChannel = 0; currentChannel < song.Channels; currentChannel++) { lastInstrument[currentChannel] = string.Empty; lastEnvelopes[currentChannel] = null; } List<string> notesWithTempoModifier = new List<string>(); for (int currentChannel = 0; currentChannel < song.Channels; currentChannel++) { noteLen = 0; lastNoteSilence = false; o = 0; d = 0; dSeminote = 0; sbyte? volModifier = null; sbyte tempoModifier; List<byte> bytesPatron = new List<byte>(); bool calculatingFirstNoteOffset = false; int firstNoteOffsetInLoopToPattern = -1; for (int currentPattern = 0; currentPattern < song.PlayOrder.Count; currentPattern++) { current = song.Patterns[song.PlayOrder[currentPattern]]; if (song.Looped && currentPattern == song.LoopToPattern) { calculatingFirstNoteOffset = true; firstNoteOffsetInLoopToPattern = 0; } for (int currentLine = 0; currentLine < current.Length; currentLine++) { ChannelLine line = current.Lines[currentLine]; note = line.Notes[currentChannel]; tempoModifier = 0; if (note.HasValue) { if (noteLen > 0) { noteLen = addNote(bytesPatron, noteLen, lastNoteSilence, d, dSeminote, o); } if (calculatingFirstNoteOffset && song.Looped) { loopLocations[currentChannel] = bytesPatron.Count; // + bytesAntesDeInstrumento.Count; firstNoteOffsetInLoopToPattern += currentLine; calculatingFirstNoteOffset = false; } } if (note.HasOctave) { o = note.Octave - 2; } if (note.HasNote) { dSeminote = 0; if (note.Note == 'P') { lastNoteSilence = true; } else { lastNoteSilence = false; d = getNote(note.Note); } volModifier = note.VolModifier; string key = string.Format("{0}_{1}", currentPattern, currentLine); if (!notesWithTempoModifier.Contains(key)) { tempoModifier = line.TempoModifier; if (tempoModifier != 0) { notesWithTempoModifier.Add(key); } } else { tempoModifier = 0; } } if (note.HasSeminote) { if (note.Seminote == '+') dSeminote = 1; else dSeminote = -1; } if (note.HasInstrument || note.VolModifier.HasValue || tempoModifier != 0) { if (note.VolModifier.HasValue || note.Instrument != lastInstrument[currentChannel] || (note.IsSawtooth && !EnvelopeData.Compare(note.EnvData, lastEnvelopes[currentChannel]))) { if (note.Instrument.ToUpper() == "R") { bytesPatron.Add(0xbf); bytesPatron.Add(getSawtoothParamsByte(note)); lastEnvelopes[currentChannel] = note.EnvData; } else { bytesPatron.Add(0x3f); bytesPatron.Add(note.HasInstrument ? byte.Parse(note.Instrument) : byte.Parse(lastInstrument[currentChannel])); byte tModifier = tempoModifier == -1 ? (byte)(1 << 5) : tempoModifier == 1 ? (byte)(1 << 6) : (byte)0; byte modifiers = (byte)((note.VolModifier.GetValueOrDefault() & 0x1F) | tModifier); bytesPatron.Add(modifiers); lastEnvelopes[currentChannel] = null; } if (note.HasInstrument) { lastInstrument[currentChannel] = note.Instrument; } } } noteLen++; } // Calculamos la longitud de la última nota haciendo que añada la longitud del canal actual completo // si en este canal no hay notas, a la espera de encontrar una nota en este canal. if (calculatingFirstNoteOffset) { firstNoteOffsetInLoopToPattern += current.Length; } } if (noteLen > 0 && bytesPatron.Count > 0) { noteLen = addNote(bytesPatron, noteLen + ((song.Looped && firstNoteOffsetInLoopToPattern >= 0) ? firstNoteOffsetInLoopToPattern : 0), lastNoteSilence, d, dSeminote, o); } // Si no se ha encontrado aún una nota a la que saltar cuando hay loop, entonces el salto del loop es // al final del canal. if (calculatingFirstNoteOffset) { loopLocations[currentChannel] = bytesPatron.Count; } if (bytesPatron.Count == 0) { bytesPatron.Add(0xC1); } bytes.AddRange(bytesPatron); bytes.Add(0x00); // Fin de canal. } // Canal de FX!!! List<byte> bytesFX = new List<byte>(); int currentFx = int.MinValue; noteLen = 0; bool calculatingFirstFxOffset = false; int firstFxOffsetInLoopToPattern = -1; for (int currentPattern = 0; currentPattern < song.PlayOrder.Count; currentPattern++) { if (song.Looped && currentPattern == song.LoopToPattern) { calculatingFirstFxOffset = true; firstFxOffsetInLoopToPattern = 0; } current = song.Patterns[song.PlayOrder[currentPattern]]; for (int currentNote = 0; currentNote < current.Length; currentNote++) { // Ver cómo se tiene que generar los FX. if (current.Lines[currentNote].Fx != int.MinValue && noteLen > 0) { noteLen = addFX(bytesFX, noteLen, currentFx, song); } if (current.Lines[currentNote].Fx != int.MinValue) { currentFx = current.Lines[currentNote].Fx; if (song.Looped && calculatingFirstFxOffset) { calculatingFirstFxOffset = false; firstFxOffsetInLoopToPattern += currentNote; loopLocations[song.Channels] = bytesFX.Count; } } noteLen++; } if (calculatingFirstFxOffset) { firstFxOffsetInLoopToPattern += current.Length; } } if (noteLen > 0 && currentFx >= 0) { noteLen = addFX(bytesFX, noteLen + ((song.Looped && firstFxOffsetInLoopToPattern >= 0) ? firstFxOffsetInLoopToPattern : 0), currentFx, song); } if (calculatingFirstFxOffset) { loopLocations[song.Channels] = bytesFX.Count; } if (bytesFX.Count == 0) { bytesFX.Add(0xC1); } bytes.AddRange(bytesFX); bytes.Add(0x00); // Fin de canal. bytes.Add(0x00); // Fin de canción. (¿¿Hace falta??) for (int c = 0; c <= song.Channels; ++c) { bytes[offsetLoopLocations + 2 * c] = (byte)(loopLocations[c] & 0x00FF); bytes[offsetLoopLocations + (2 * c) + 1] = (byte)((loopLocations[c] & 0x0FF00) >> 8); } return bytes.ToArray(); }
public static byte[] GenerateSong(Song song) { List <byte> bytes = new List <byte>(); Pattern current; ChannelNote note; int noteLen; bool lastNoteSilence; string[] lastInstrument = new string[song.Channels]; EnvelopeData[] lastEnvelopes = new EnvelopeData[song.Channels]; int[] loopLocations = new int[song.Channels + 1]; int d; int dSeminote; int o; bytes.Add(song.Tempo); byte headerByte = (byte)(song.Looped ? 0x01 : 0x00); headerByte |= (byte)((song.FxChannel & 0x7) << 1); headerByte |= (byte)((song.Channels & 0x7) << 4); bytes.Add(headerByte); // Dos bytes reservados (de momento). bytes.Add(0); bytes.Add(0); // Metemos los bytes de offset de loops. int offsetLoopLocations = bytes.Count; bytes.AddRange(new byte[2 * (song.Channels + 1)]); for (int currentChannel = 0; currentChannel < song.Channels; currentChannel++) { lastInstrument[currentChannel] = string.Empty; lastEnvelopes[currentChannel] = null; } List <string> notesWithTempoModifier = new List <string>(); for (int currentChannel = 0; currentChannel < song.Channels; currentChannel++) { noteLen = 0; lastNoteSilence = false; o = 0; d = 0; dSeminote = 0; sbyte? volModifier = null; sbyte tempoModifier; List <byte> bytesPatron = new List <byte>(); bool calculatingFirstNoteOffset = false; int firstNoteOffsetInLoopToPattern = -1; for (int currentPattern = 0; currentPattern < song.PlayOrder.Count; currentPattern++) { current = song.Patterns[song.PlayOrder[currentPattern]]; if (song.Looped && currentPattern == song.LoopToPattern) { calculatingFirstNoteOffset = true; firstNoteOffsetInLoopToPattern = 0; } for (int currentLine = 0; currentLine < current.Length; currentLine++) { ChannelLine line = current.Lines[currentLine]; note = line.Notes[currentChannel]; tempoModifier = 0; if (note.HasValue) { if (noteLen > 0) { noteLen = addNote(bytesPatron, noteLen, lastNoteSilence, d, dSeminote, o); } if (calculatingFirstNoteOffset && song.Looped) { loopLocations[currentChannel] = bytesPatron.Count; // + bytesAntesDeInstrumento.Count; firstNoteOffsetInLoopToPattern += currentLine; calculatingFirstNoteOffset = false; } } if (note.HasOctave) { o = note.Octave - 2; } if (note.HasNote) { dSeminote = 0; if (note.Note == 'P') { lastNoteSilence = true; } else { lastNoteSilence = false; d = getNote(note.Note); } volModifier = note.VolModifier; string key = string.Format("{0}_{1}", currentPattern, currentLine); if (!notesWithTempoModifier.Contains(key)) { tempoModifier = line.TempoModifier; if (tempoModifier != 0) { notesWithTempoModifier.Add(key); } } else { tempoModifier = 0; } } if (note.HasSeminote) { if (note.Seminote == '+') { dSeminote = 1; } else { dSeminote = -1; } } if (note.HasInstrument || note.VolModifier.HasValue || tempoModifier != 0) { if (note.VolModifier.HasValue || note.Instrument != lastInstrument[currentChannel] || (note.IsSawtooth && !EnvelopeData.Compare(note.EnvData, lastEnvelopes[currentChannel]))) { if (note.Instrument.ToUpper() == "R") { bytesPatron.Add(0xbf); bytesPatron.Add(getSawtoothParamsByte(note)); lastEnvelopes[currentChannel] = note.EnvData; } else { bytesPatron.Add(0x3f); bytesPatron.Add(note.HasInstrument ? byte.Parse(note.Instrument) : byte.Parse(lastInstrument[currentChannel])); byte tModifier = tempoModifier == -1 ? (byte)(1 << 5) : tempoModifier == 1 ? (byte)(1 << 6) : (byte)0; byte modifiers = (byte)((note.VolModifier.GetValueOrDefault() & 0x1F) | tModifier); bytesPatron.Add(modifiers); lastEnvelopes[currentChannel] = null; } if (note.HasInstrument) { lastInstrument[currentChannel] = note.Instrument; } } } noteLen++; } // Calculamos la longitud de la última nota haciendo que añada la longitud del canal actual completo // si en este canal no hay notas, a la espera de encontrar una nota en este canal. if (calculatingFirstNoteOffset) { firstNoteOffsetInLoopToPattern += current.Length; } } if (noteLen > 0 && bytesPatron.Count > 0) { noteLen = addNote(bytesPatron, noteLen + ((song.Looped && firstNoteOffsetInLoopToPattern >= 0) ? firstNoteOffsetInLoopToPattern : 0), lastNoteSilence, d, dSeminote, o); } // Si no se ha encontrado aún una nota a la que saltar cuando hay loop, entonces el salto del loop es // al final del canal. if (calculatingFirstNoteOffset) { loopLocations[currentChannel] = bytesPatron.Count; } if (bytesPatron.Count == 0) { bytesPatron.Add(0xC1); } bytes.AddRange(bytesPatron); bytes.Add(0x00); // Fin de canal. } // Canal de FX!!! List <byte> bytesFX = new List <byte>(); int currentFx = int.MinValue; noteLen = 0; bool calculatingFirstFxOffset = false; int firstFxOffsetInLoopToPattern = -1; for (int currentPattern = 0; currentPattern < song.PlayOrder.Count; currentPattern++) { if (song.Looped && currentPattern == song.LoopToPattern) { calculatingFirstFxOffset = true; firstFxOffsetInLoopToPattern = 0; } current = song.Patterns[song.PlayOrder[currentPattern]]; for (int currentNote = 0; currentNote < current.Length; currentNote++) { // Ver cómo se tiene que generar los FX. if (current.Lines[currentNote].Fx != int.MinValue && noteLen > 0) { noteLen = addFX(bytesFX, noteLen, currentFx, song); } if (current.Lines[currentNote].Fx != int.MinValue) { currentFx = current.Lines[currentNote].Fx; if (song.Looped && calculatingFirstFxOffset) { calculatingFirstFxOffset = false; firstFxOffsetInLoopToPattern += currentNote; loopLocations[song.Channels] = bytesFX.Count; } } noteLen++; } if (calculatingFirstFxOffset) { firstFxOffsetInLoopToPattern += current.Length; } } if (noteLen > 0 && currentFx >= 0) { noteLen = addFX(bytesFX, noteLen + ((song.Looped && firstFxOffsetInLoopToPattern >= 0) ? firstFxOffsetInLoopToPattern : 0), currentFx, song); } if (calculatingFirstFxOffset) { loopLocations[song.Channels] = bytesFX.Count; } if (bytesFX.Count == 0) { bytesFX.Add(0xC1); } bytes.AddRange(bytesFX); bytes.Add(0x00); // Fin de canal. bytes.Add(0x00); // Fin de canción. (¿¿Hace falta??) for (int c = 0; c <= song.Channels; ++c) { bytes[offsetLoopLocations + 2 * c] = (byte)(loopLocations[c] & 0x00FF); bytes[offsetLoopLocations + (2 * c) + 1] = (byte)((loopLocations[c] & 0x0FF00) >> 8); } return(bytes.ToArray()); }