public SoundFontSampleData(IReadable input) { var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "list") throw new Exception("Invalid soundfont. Could not find sdta LIST chunk."); var readTo = input.Position + size; id = input.Read8BitChars(4); if (id.ToLower() != "sdta") throw new Exception("Invalid soundfont. The LIST chunk is not of type sdta."); BitsPerSample = 0; byte[] rawSampleData = null; while (input.Position < readTo) { var subID = input.Read8BitChars(4); size = input.ReadInt32LE(); switch (subID.ToLower()) { case "smpl": BitsPerSample = 16; rawSampleData = input.ReadByteArray(size); break; case "sm24": if (rawSampleData == null || size != Math.Ceiling(SampleData.Length / 2.0)) {//ignore this chunk if wrong size or if it comes first input.Skip(size); } else { BitsPerSample = 24; for (var x = 0; x < SampleData.Length; x++) { var b = new byte[3]; b[0] = (byte)input.ReadByte(); b[1] = rawSampleData[2 * x]; b[2] = rawSampleData[2 * x + 1]; } } if (size % 2 == 1) { if (input.ReadByte() != 0) { input.Position--; } } break; default: throw new Exception("Invalid soundfont. Unknown chunk id: " + subID + "."); } } if (BitsPerSample == 16) { SampleData = rawSampleData; } else if (BitsPerSample != 24) throw new Exception("Only 16 and 24 bit samples are supported."); }
public void Load(IReadable input) { var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "riff") throw new Exception("Invalid soundfont. Could not find RIFF header."); id = input.Read8BitChars(4); if (id.ToLower() != "sfbk") throw new Exception("Invalid soundfont. Riff type is invalid."); Logger.Debug("Reading info chunk"); Info = new SoundFontInfo(input); Logger.Debug("Reading sampledata chunk"); SampleData = new SoundFontSampleData(input); Logger.Debug("Reading preset chunk"); Presets = new SoundFontPresets(input); }
public void Load(IReadable input) { var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "riff") { throw new Exception("Invalid soundfont. Could not find RIFF header."); } id = input.Read8BitChars(4); if (id.ToLower() != "sfbk") { throw new Exception("Invalid soundfont. Riff type is invalid."); } Logger.Debug("SF2", "Reading info chunk"); Info = new SoundFontInfo(input); Logger.Debug("SF2", "Reading sampledata chunk"); SampleData = new SoundFontSampleData(input); Logger.Debug("SF2", "Reading preset chunk"); Presets = new SoundFontPresets(input); }
public SoundFontSampleData(IReadable input) { var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "list") { throw new Exception("Invalid soundfont. Could not find sdta LIST chunk."); } var readTo = input.Position + size; id = input.Read8BitChars(4); if (id.ToLower() != "sdta") { throw new Exception("Invalid soundfont. The LIST chunk is not of type sdta."); } BitsPerSample = 0; byte[] rawSampleData = null; while (input.Position < readTo) { var subID = input.Read8BitChars(4); size = input.ReadInt32LE(); switch (subID.ToLower()) { case "smpl": BitsPerSample = 16; rawSampleData = input.ReadByteArray(size); break; case "sm24": if (rawSampleData == null || size != Math.Ceiling(SampleData.Length / 2.0)) { //ignore this chunk if wrong size or if it comes first input.Skip(size); } else { BitsPerSample = 24; for (var x = 0; x < SampleData.Length; x++) { var b = new byte[3]; b[0] = (byte)input.ReadByte(); b[1] = rawSampleData[2 * x]; b[2] = rawSampleData[2 * x + 1]; } } if (size % 2 == 1) { if (input.ReadByte() != 0) { input.Position--; } } break; default: throw new Exception("Invalid soundfont. Unknown chunk id: " + subID + "."); } } if (BitsPerSample == 16) { SampleData = rawSampleData; } else if (BitsPerSample != 24) { throw new Exception("Only 16 and 24 bit samples are supported."); } }
private static string ReadString(IReadable input) { var length = ReadVariableLength(input); return(input.Read8BitChars(length)); // TODO: check for correct string encoding }
private MidiTrack ReadTrack(IReadable input) { var instList = new FastList <Byte>(); var drumList = new FastList <Byte>(); var channelList = new FastList <Byte>(); var eventList = new FastList <MidiEvent>(); var noteOnCount = 0; var totalTime = 0; while (input.Read8BitChars(4) != "MTrk") { var length = input.ReadInt32BE(); while (length > 0) { length--; input.ReadByte(); } } var endPosition = input.ReadInt32BE() + input.Position; var prevStatus = 0; while (input.Position < endPosition) { var delta = ReadVariableLength(input); totalTime += delta; var status = input.ReadByte(); if (status >= 0x80 && status <= 0xEF) {//voice message prevStatus = status; eventList.Add(ReadVoiceMessage(input, delta, (byte)status, (byte)input.ReadByte())); noteOnCount = TrackVoiceStats(eventList[eventList.Count - 1], instList, drumList, channelList, noteOnCount); } else if (status >= 0xF0 && status <= 0xF7) {//system common message prevStatus = 0; eventList.Add(ReadSystemCommonMessage(input, delta, (byte)status)); } else if (status >= 0xF8 && status <= 0xFF) {//realtime message eventList.Add(ReadRealTimeMessage(input, delta, (byte)status)); } else { //data bytes if (prevStatus == 0) { //if no running status continue to next status byte while ((status & 0x80) != 0x80) { status = input.ReadByte(); } if (status >= 0x80 && status <= 0xEF) {//voice message prevStatus = status; eventList.Add(ReadVoiceMessage(input, delta, (byte)status, (byte)input.ReadByte())); noteOnCount = TrackVoiceStats(eventList[eventList.Count - 1], instList, drumList, channelList, noteOnCount); } else if (status >= 0xF0 && status <= 0xF7) {//system common message eventList.Add(ReadSystemCommonMessage(input, delta, (byte)status)); } else if (status >= 0xF8 && status <= 0xFF) {//realtime message eventList.Add(ReadRealTimeMessage(input, delta, (byte)status)); } } else {//otherwise apply running status eventList.Add(ReadVoiceMessage(input, delta, (byte)prevStatus, (byte)status)); noteOnCount = TrackVoiceStats(eventList[eventList.Count - 1], instList, drumList, channelList, noteOnCount); } } } if (input.Position != endPosition) { throw new Exception("The track length was invalid for the current MTrk chunk."); } if (channelList.IndexOf(MidiHelper.DrumChannel) != -1) { if (drumList.IndexOf(0) == -1) { drumList.Add(0); } } else { if (instList.IndexOf(0) == -1) { instList.Add(0); } } var track = new MidiTrack(instList.ToArray(), drumList.ToArray(), channelList.ToArray(), eventList.ToArray()); track.NoteOnCount = noteOnCount; track.EndTime = totalTime; return(track); }
public SoundFontPresets(IReadable input) { var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "list") { throw new Exception("Invalid soundfont. Could not find pdta LIST chunk."); } var readTo = input.Position + size; id = input.Read8BitChars(4); if (id.ToLower() != "pdta") { throw new Exception("Invalid soundfont. The LIST chunk is not of type pdta."); } Modulator[] presetModulators = null; Generator[] presetGenerators = null; Modulator[] instrumentModulators = null; Generator[] instrumentGenerators = null; ZoneChunk pbag = null; ZoneChunk ibag = null; PresetHeaderChunk phdr = null; InstrumentChunk inst = null; while (input.Position < readTo) { id = input.Read8BitChars(4); size = input.ReadInt32LE(); switch (id.ToLower()) { case "phdr": phdr = new PresetHeaderChunk(id, size, input); break; case "pbag": pbag = new ZoneChunk(id, size, input); break; case "pmod": presetModulators = new ModulatorChunk(id, size, input).Modulators; break; case "pgen": presetGenerators = new GeneratorChunk(id, size, input).Generators; break; case "inst": inst = new InstrumentChunk(id, size, input); break; case "ibag": ibag = new ZoneChunk(id, size, input); break; case "imod": instrumentModulators = new ModulatorChunk(id, size, input).Modulators; break; case "igen": instrumentGenerators = new GeneratorChunk(id, size, input).Generators; break; case "shdr": SampleHeaders = new SampleHeaderChunk(id, size, input).SampleHeaders; break; default: throw new Exception("Invalid soundfont. Unrecognized sub chunk: " + id); } } var pZones = pbag.ToZones(presetModulators, presetGenerators); PresetHeaders = phdr.ToPresets(pZones); var iZones = ibag.ToZones(instrumentModulators, instrumentGenerators); Instruments = inst.ToInstruments(iZones); }
public SoundFontInfo(IReadable input) { Tools = ""; Comments = ""; Copyright = ""; TargetProduct = ""; Author = ""; DataRom = ""; CreationDate = ""; BankName = ""; SoundEngine = ""; var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "list") { throw new Exception("Invalid soundfont. Could not find INFO LIST chunk."); } var readTo = input.Position + size; id = input.Read8BitChars(4); if (id.ToLower() != "info") { throw new Exception("Invalid soundfont. The LIST chunk is not of type INFO."); } while (input.Position < readTo) { id = input.Read8BitChars(4); size = input.ReadInt32LE(); switch (id.ToLower()) { case "ifil": SfVersionMajor = input.ReadInt16LE(); SfVersionMinor = input.ReadInt16LE(); break; case "isng": SoundEngine = input.Read8BitStringLength(size); break; case "inam": BankName = input.Read8BitStringLength(size); break; case "irom": DataRom = input.Read8BitStringLength(size); break; case "iver": RomVersionMajor = input.ReadInt16LE(); RomVersionMinor = input.ReadInt16LE(); break; case "icrd": CreationDate = input.Read8BitStringLength(size); break; case "ieng": Author = input.Read8BitStringLength(size); break; case "iprd": TargetProduct = input.Read8BitStringLength(size); break; case "icop": Copyright = input.Read8BitStringLength(size); break; case "icmt": Comments = input.Read8BitStringLength(size); break; case "isft": Tools = input.Read8BitStringLength(size); break; default: throw new Exception("Invalid soundfont. The Chunk: " + id + " was not expected."); } } }
public SoundFontPresets(IReadable input) { var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "list") throw new Exception("Invalid soundfont. Could not find pdta LIST chunk."); var readTo = input.Position + size; id = input.Read8BitChars(4); if (id.ToLower() != "pdta") throw new Exception("Invalid soundfont. The LIST chunk is not of type pdta."); Modulator[] presetModulators = null; Generator[] presetGenerators = null; Modulator[] instrumentModulators = null; Generator[] instrumentGenerators = null; ZoneChunk pbag = null; ZoneChunk ibag = null; PresetHeaderChunk phdr = null; InstrumentChunk inst = null; while (input.Position < readTo) { id = input.Read8BitChars(4); size = input.ReadInt32LE(); switch (id.ToLower()) { case "phdr": phdr = new PresetHeaderChunk(id, size, input); break; case "pbag": pbag = new ZoneChunk(id, size, input); break; case "pmod": presetModulators = new ModulatorChunk(id, size, input).Modulators; break; case "pgen": presetGenerators = new GeneratorChunk(id, size, input).Generators; break; case "inst": inst = new InstrumentChunk(id, size, input); break; case "ibag": ibag = new ZoneChunk(id, size, input); break; case "imod": instrumentModulators = new ModulatorChunk(id, size, input).Modulators; break; case "igen": instrumentGenerators = new GeneratorChunk(id, size, input).Generators; break; case "shdr": SampleHeaders = new SampleHeaderChunk(id, size, input).SampleHeaders; break; default: throw new Exception("Invalid soundfont. Unrecognized sub chunk: " + id); } } var pZones = pbag.ToZones(presetModulators, presetGenerators); PresetHeaders = phdr.ToPresets(pZones); var iZones = ibag.ToZones(instrumentModulators, instrumentGenerators); Instruments = inst.ToInstruments(iZones); }
public SoundFontInfo(IReadable input) { Tools = ""; Comments = ""; Copyright = ""; TargetProduct = ""; Author = ""; DataRom = ""; CreationDate = ""; BankName = ""; SoundEngine = ""; var id = input.Read8BitChars(4); var size = input.ReadInt32LE(); if (id.ToLower() != "list") throw new Exception("Invalid soundfont. Could not find INFO LIST chunk."); var readTo = input.Position + size; id = input.Read8BitChars(4); if (id.ToLower() != "info") throw new Exception("Invalid soundfont. The LIST chunk is not of type INFO."); while (input.Position < readTo) { id = input.Read8BitChars(4); size = input.ReadInt32LE(); switch (id.ToLower()) { case "ifil": SfVersionMajor = input.ReadInt16LE(); SfVersionMinor = input.ReadInt16LE(); break; case "isng": SoundEngine = input.Read8BitStringLength(size); break; case "inam": BankName = input.Read8BitStringLength(size); break; case "irom": DataRom = input.Read8BitStringLength(size); break; case "iver": RomVersionMajor = input.ReadInt16LE(); RomVersionMinor = input.ReadInt16LE(); break; case "icrd": CreationDate = input.Read8BitStringLength(size); break; case "ieng": Author = input.Read8BitStringLength(size); break; case "iprd": TargetProduct = input.Read8BitStringLength(size); break; case "icop": Copyright = input.Read8BitStringLength(size); break; case "icmt": Comments = input.Read8BitStringLength(size); break; case "isft": Tools = input.Read8BitStringLength(size); break; default: throw new Exception("Invalid soundfont. The Chunk: " + id + " was not expected."); } } }
private static string ReadString(IReadable input) { var length = ReadVariableLength(input); return input.Read8BitChars(length); // TODO: check for correct string encoding }
private MidiTrack ReadTrack(IReadable input) { var instList = new FastList<Byte>(); var drumList = new FastList<Byte>(); var channelList = new FastList<Byte>(); var eventList = new FastList<MidiEvent>(); var noteOnCount = 0; var totalTime = 0; while (input.Read8BitChars(4) != "MTrk") { var length = input.ReadInt32BE(); while (length > 0) { length--; input.ReadByte(); } } var endPosition = input.ReadInt32BE() + input.Position; var prevStatus = 0; while (input.Position < endPosition) { var delta = ReadVariableLength(input); totalTime += delta; var status = input.ReadByte(); if (status >= 0x80 && status <= 0xEF) {//voice message prevStatus = status; eventList.Add(ReadVoiceMessage(input, delta, (byte)status, (byte)input.ReadByte())); noteOnCount = TrackVoiceStats(eventList[eventList.Count - 1], instList, drumList, channelList, noteOnCount); } else if (status >= 0xF0 && status <= 0xF7) {//system common message prevStatus = 0; eventList.Add(ReadSystemCommonMessage(input, delta, (byte)status)); } else if (status >= 0xF8 && status <= 0xFF) {//realtime message eventList.Add(ReadRealTimeMessage(input, delta, (byte)status)); } else {//data bytes if (prevStatus == 0) {//if no running status continue to next status byte while ((status & 0x80) != 0x80) { status = input.ReadByte(); } if (status >= 0x80 && status <= 0xEF) {//voice message prevStatus = status; eventList.Add(ReadVoiceMessage(input, delta, (byte)status, (byte)input.ReadByte())); noteOnCount = TrackVoiceStats(eventList[eventList.Count - 1], instList, drumList, channelList, noteOnCount); } else if (status >= 0xF0 && status <= 0xF7) {//system common message eventList.Add(ReadSystemCommonMessage(input, delta, (byte)status)); } else if (status >= 0xF8 && status <= 0xFF) {//realtime message eventList.Add(ReadRealTimeMessage(input, delta, (byte)status)); } } else {//otherwise apply running status eventList.Add(ReadVoiceMessage(input, delta, (byte)prevStatus, (byte)status)); noteOnCount = TrackVoiceStats(eventList[eventList.Count - 1], instList, drumList, channelList, noteOnCount); } } } if (input.Position != endPosition) throw new Exception("The track length was invalid for the current MTrk chunk."); if (channelList.IndexOf(MidiHelper.DrumChannel) != -1) { if (drumList.IndexOf(0) == -1) drumList.Add(0); } else { if (instList.IndexOf(0) == -1) instList.Add(0); } var track = new MidiTrack(instList.ToArray(), drumList.ToArray(), channelList.ToArray(), eventList.ToArray()); track.NoteOnCount = noteOnCount; track.EndTime = totalTime; return track; }