/// <summary> /// Exports the current <see cref="Pattern"/> to track chunk. /// </summary> /// <param name="tempoMap">Tempo map to process pattern data according with.</param> /// <param name="channel">Channel of notes that will be generated by pattern.</param> /// <returns>The <see cref="TrackChunk"/> containing notes events generated by the current <see cref="Pattern"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="tempoMap"/> is null.</exception> public TrackChunk ToTrackChunk(TempoMap tempoMap, FourBitNumber channel) { ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); var context = new PatternContext(tempoMap, channel); var result = InvokeActions(0, context); // var trackChunk = new TrackChunk(); using (var notesManager = trackChunk.ManageNotes()) { notesManager.Notes.Add(result.Notes ?? Enumerable.Empty <Note>()); } using (var eventsManager = trackChunk.ManageTimedEvents()) { eventsManager.Events.Add(result.Events ?? Enumerable.Empty <TimedEvent>()); } // return(trackChunk); }
public NoteDescriptor(long startTime, long endTime, FourBitNumber channel, SevenBitNumber noteNumber) { StartTime = startTime; EndTime = endTime; Channel = channel; NoteNumber = noteNumber; }
/// <summary> /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events that will be /// produced by specified <see cref="Pattern"/>. /// </summary> /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param> /// <param name="tempoMap">Tempo map used to calculate events times.</param> /// <param name="channel">MIDI channel to play channel events on.</param> /// <param name="clockSettings">Settings of the internal playback's clock.</param> /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events that will be /// produced by the <paramref name="pattern"/>.</returns> /// <exception cref="ArgumentNullException"> /// <para>One of the following errors occured:</para> /// <list type="bullet"> /// <item> /// <description><paramref name="pattern"/> is <c>null</c>.</description> /// </item> /// <item> /// <description><paramref name="tempoMap"/> is <c>null</c>.</description> /// </item> /// </list> /// </exception> public static Playback GetPlayback(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, MidiClockSettings clockSettings = null) { ThrowIfArgument.IsNull(nameof(pattern), pattern); ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); return(pattern.ToTrackChunk(tempoMap, channel).GetPlayback(tempoMap, clockSettings)); }
internal override void Read(MidiReader reader, ReadingSettings settings, int size) { var data = reader.ReadByte(); var midiTimeCodeComponent = (byte)data.GetHead(); if (!Enum.IsDefined(typeof(MidiTimeCodeComponent), midiTimeCodeComponent)) { throw new InvalidMidiTimeCodeComponentException(midiTimeCodeComponent); } Component = (MidiTimeCodeComponent)midiTimeCodeComponent; var componentValue = data.GetTail(); if (componentValue > ComponentValueMasks[Component]) { switch (settings.InvalidSystemCommonEventParameterValuePolicy) { case InvalidSystemCommonEventParameterValuePolicy.Abort: throw new InvalidSystemCommonEventParameterValueException(EventType, $"{nameof(ComponentValue)} (component is {Component})", componentValue); case InvalidSystemCommonEventParameterValuePolicy.SnapToLimits: componentValue = (FourBitNumber)ComponentValueMasks[Component]; break; } } ComponentValue = componentValue; }
public void TryParse_OutOfRange() { FourBitNumber result; Assert.AreEqual(false, FourBitNumber.TryParse("200", out result)); Assert.AreEqual(false, FourBitNumber.TryParse("16", out result)); }
private bool TryAddObjectToNewNoteBag(ITimedObject timedObject, ObjectsBuildingSettings settings) { var bag = new NotesBag(); if (!bag.TryAddObject(timedObject, null, settings)) { return(false); } var newNoteTime = bag.Time; var newNoteChannel = bag.NoteId.Channel; if (_chordStart < 0) { _notesBags.Add(bag); _chordStart = newNoteTime; _chordChannel = newNoteChannel; return(true); } else { if (newNoteTime - _chordStart > settings.ChordBuilderSettings.NotesTolerance || newNoteChannel != _chordChannel) { _canObjectsBeAdded = !IsCompleted; return(false); } _notesBags.Add(bag); return(true); } }
private void ReactOnUnknownChannelEvent(FourBitNumber statusByte, FourBitNumber channel, MidiReader reader, ReadingSettings settings) { switch (settings.UnknownChannelEventPolicy) { case UnknownChannelEventPolicy.Abort: throw new UnknownChannelEventException(statusByte, channel); case UnknownChannelEventPolicy.SkipStatusByte: return; case UnknownChannelEventPolicy.SkipStatusByteAndOneDataByte: reader.Position += 1; return; case UnknownChannelEventPolicy.SkipStatusByteAndTwoDataBytes: reader.Position += 2; return; case UnknownChannelEventPolicy.UseCallback: var callback = settings.UnknownChannelEventCallback; var action = callback(statusByte, channel); switch (action.Instruction) { case UnknownChannelEventInstruction.Abort: throw new UnknownChannelEventException(statusByte, channel); case UnknownChannelEventInstruction.SkipData: reader.Position += action.DataBytesToSkip; return; } break; } }
/// <summary> /// Retrieves an instance of the <see cref="Playback"/> for playing MIDI events that will be /// produced by specified <see cref="Pattern"/>. /// </summary> /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param> /// <param name="tempoMap">Tempo map used to calculate events times.</param> /// <param name="channel">MIDI channel to play channel events on.</param> /// <param name="outputDevice">Output MIDI device to play events through.</param> /// <returns>An instance of the <see cref="Playback"/> for playing MIDI events that will be /// produced by the <paramref name="pattern"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="pattern"/> is null. -or- /// <paramref name="tempoMap"/> is null. -or- <paramref name="outputDevice"/> is null.</exception> public static Playback GetPlayback(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, OutputDevice outputDevice) { ThrowIfArgument.IsNull(nameof(pattern), pattern); ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice); return(pattern.ToTrackChunk(tempoMap, channel).GetPlayback(tempoMap, outputDevice)); }
private static bool IsAppropriateNoteOnTimedEvent(TimedEvent timedEvent, FourBitNumber channel, SevenBitNumber noteNumber) { var noteOnEvent = timedEvent.Event as NoteOnEvent; return(noteOnEvent != null && noteOnEvent.Channel == channel && noteOnEvent.NoteNumber == noteNumber); }
/// <summary> /// Plays MIDI events that will be produced by specified <see cref="Pattern"/>. /// </summary> /// <param name="pattern"><see cref="Pattern"/> producing events to play.</param> /// <param name="tempoMap">Tempo map used to calculate events times.</param> /// <param name="channel">MIDI channel to play channel events on.</param> /// <param name="outputDevice">Output MIDI device to play events through.</param> /// <param name="clockSettings">Settings of the internal playback's clock.</param> /// <exception cref="ArgumentNullException"> /// <para>One of the following errors occured:</para> /// <list type="bullet"> /// <item> /// <description><paramref name="pattern"/> is <c>null</c>.</description> /// </item> /// <item> /// <description><paramref name="tempoMap"/> is <c>null</c>.</description> /// </item> /// <item> /// <description><paramref name="outputDevice"/> is <c>null</c>.</description> /// </item> /// </list> /// </exception> public static void Play(this Pattern pattern, TempoMap tempoMap, FourBitNumber channel, IOutputDevice outputDevice, MidiClockSettings clockSettings = null) { ThrowIfArgument.IsNull(nameof(pattern), pattern); ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); ThrowIfArgument.IsNull(nameof(outputDevice), outputDevice); pattern.ToTrackChunk(tempoMap, channel).Play(tempoMap, outputDevice, clockSettings); }
public NotePlaybackData(SevenBitNumber noteNumber, SevenBitNumber velocity, SevenBitNumber offVelocity, FourBitNumber channel) : this(true) { NoteNumber = noteNumber; Velocity = velocity; OffVelocity = offVelocity; Channel = channel; }
/// <summary> /// Gets an instance of the <see cref="ProgramChangeEvent"/> corresponding to the specified /// General MIDI Level 1 program. /// </summary> /// <param name="program"><see cref="GeneralMidiProgram"/> to get an event for.</param> /// <param name="channel">Channel an event should be created for.</param> /// <returns>An instance of the <see cref="ProgramChangeEvent"/> corresponding to the <paramref name="program"/>.</returns> /// <exception cref="InvalidEnumArgumentException"><paramref name="program"/> specified an invalid value.</exception> public static MidiEvent GetProgramEvent(this GeneralMidiProgram program, FourBitNumber channel) { ThrowIfArgument.IsInvalidEnumValue(nameof(program), program); return(new ProgramChangeEvent(program.AsSevenBitNumber()) { Channel = channel }); }
/// <summary> /// Gets the play times of notes associated with the selected instrument. /// </summary> /// <param name="instrument">Instrument to retrieve note times for.</param> /// <returns>Note times for instrument.</returns> public List <long> RetrieveNoteTimesForInstrument(FourBitNumber instrument) { var midiMap = this.midi.GetTempoMap(); return(this.midi.GetNotes() .Where(note => note.Channel == instrument) .Select(note => ((MetricTimeSpan)note.TimeAs(TimeSpanType.Metric, midiMap)).TotalMicroseconds / 1000) .Distinct() .ToList()); }
/// <summary> /// Exports the current <see cref="Pattern"/> to track chunk. /// </summary> /// <param name="tempoMap">Tempo map to process pattern data according with.</param> /// <param name="channel">Channel of notes that will be generated by pattern.</param> /// <returns>The <see cref="TrackChunk"/> containing notes events generated by the current <see cref="Pattern"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="tempoMap"/> is <c>null</c>.</exception> public TrackChunk ToTrackChunk(TempoMap tempoMap, FourBitNumber channel) { ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); var context = new PatternContext(tempoMap, channel); var result = InvokeActions(0, context); return(((IEnumerable <ITimedObject>)result.Events ?? Enumerable.Empty <TimedEvent>()) .Concat(result.Notes ?? Enumerable.Empty <Note>()) .ToTrackChunk()); }
/// <summary> /// Exports the current <see cref="Pattern"/> to MIDI file. /// </summary> /// <param name="tempoMap">Tempo map to process pattern data according with.</param> /// <param name="channel">Channel of notes that will be generated by pattern.</param> /// <returns>The <see cref="MidiFile"/> containing notes events generated by the current <see cref="Pattern"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="tempoMap"/> is null.</exception> public MidiFile ToFile(TempoMap tempoMap, FourBitNumber channel) { ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); var trackChunk = ToTrackChunk(tempoMap, channel); var midiFile = new MidiFile(trackChunk); midiFile.ReplaceTempoMap(tempoMap); return(midiFile); }
public void TryParse() { FourBitNumber result; FourBitNumber.TryParse("12", out result); Assert.AreEqual((FourBitNumber)12, result); FourBitNumber.TryParse("0", out result); Assert.AreEqual((FourBitNumber)0, result); FourBitNumber.TryParse("15", out result); Assert.AreEqual((FourBitNumber)15, result); }
/// <summary> /// Initializes a new instance of the <see cref="MidiTimeCodeEvent"/> with the specified /// time code component and its value. /// </summary> /// <param name="component">MIDI time code component.</param> /// <param name="componentValue">Value of <paramref name="component"/>.</param> /// <exception cref="InvalidEnumArgumentException"><paramref name="component"/> specified an /// invalid value.</exception> public MidiTimeCodeEvent(MidiTimeCodeComponent component, FourBitNumber componentValue) : this() { ThrowIfArgument.IsInvalidEnumValue(nameof(component), component); var maximumComponentValue = ComponentValueMasks[component]; ThrowIfArgument.IsGreaterThan(nameof(componentValue), componentValue, maximumComponentValue, $"Component's value is greater than maximum valid one which is {maximumComponentValue}."); Component = component; ComponentValue = componentValue; }
private IEnumerable <Note> CreateNotes(string[] timesAndLengths, SevenBitNumber noteNumber, FourBitNumber channel, TempoMap tempoMap) { var notes = ObjectMethods.CreateCollection(tempoMap, timesAndLengths); foreach (var note in notes) { note.NoteNumber = noteNumber; note.Channel = channel; } return(notes); }
private static int?GetProgramNumber(FourBitNumber channel, long time, Dictionary <FourBitNumber, Dictionary <long, SevenBitNumber> > programChanges) { Dictionary <long, SevenBitNumber> changes; if (!programChanges.TryGetValue(channel, out changes)) { return(null); } var times = changes.Keys.Where(t => t <= time).ToArray(); return(times.Any() ? (int?)changes[times.Max()] : null); }
public static void ParseAndPlay(string text, string nameSynth = null) { if (nameSynth == null) { // nameSynth = "Microsoft GS Wavetable Synth"; var devices = AllDevices(); nameSynth = devices[R.Next(0, devices.Length)]; } var g = Enum.GetValues(typeof(NoteName)); T2MJsonObject obj = null; obj = JsonConvert.DeserializeObject <T2MJsonObject>(text); var midiFile = new MidiFile(); var cmdsplit = "-".ToCharArray(); #if DEBUG StringBuilder sb = new StringBuilder(); #endif foreach (MidiTrack track in obj.Tracks) { FourBitNumber channel = (FourBitNumber)(track.Channel & 15); int velocity = track.Velocity; var instro = new ProgramChangeEvent((SevenBitNumber)track.Instrument); instro.Channel = channel; var trackChunk = new TrackChunk(instro); #if DEBUG sb.Append("Begin of Chunk" + Environment.NewLine); #endif int length = 40; using (var cm = trackChunk.ManageChords()) { ChordsCollection chords = cm.Chords; var commands = string.Join(" ", track.Commands).Split(' ', '\t', '\r', '\n'); // NoteName tpz = (NoteName)_EXT_.AllNotes.GetValue(0); // TODO Transpose as cmd int t = track.Start; int i = track.Interval; int oct = track.Octave; string cmd; foreach (string v in commands) { if (v.StartsWith("/")) { cmd = v.TrimStart('/'); if (cmd == "_") { t += i; continue; } var n0 = cmd.Split(cmdsplit, StringSplitOptions.RemoveEmptyEntries).Select(x => GetNoteName(x)); var nn = n0; //.FromTemplate(n0); // nn = nn.FromTemplate(tpz); #if DEBUG var m = string.Join(" ", nn.Select(x => x.Name.ToString().Replace("Sharp", "#") + " " + (x.Octave == -1 ? oct : x.Octave))); sb.Append(m + " /"); sb.Append(Environment.NewLine); #endif InterNote[] ni = nn.Select(x => new InterNote(x.Name, x.Octave == -1 ? oct : x.Octave, length, t) { Channel = channel, Velocity = (SevenBitNumber)(velocity & 127) }) // .Concat(new[] { new InterNote(nn.First(), oct + 1, G, t) }) .ToArray(); var chord = new IA.Chord(ni); chords.Add(chord); t += i; } else if (v.StartsWith("*")) { cmd = v.TrimStart('*'); if (int.TryParse(cmd, out int ia)) { oct = ia; } } else if (v.StartsWith("+")) { cmd = v.TrimStart('+'); if (int.TryParse(cmd, out int ia)) { i += ia; } } else if (v.StartsWith("-")) { if (int.TryParse(v, out int ia)) { i += ia; } } else if (v.StartsWith("L")) { cmd = v.TrimStart('L'); if (int.TryParse(cmd, out int ia)) { length = ia; } } else if (v == "_") { t += i; continue; } } cm.SaveChanges(); } midiFile.Chunks.Add(trackChunk); #if DEBUG sb.Append(Environment.NewLine); sb.Append("End of Chunk"); sb.Append(Environment.NewLine); #endif } var appDir = Assembly.GetExecutingAssembly().Location; appDir = Path.GetDirectoryName(appDir); var file = "Im3" + DateTime.Now.ToString("yyyy-MM-dd--HH-mm-ss") + ".mid"; file = Path.Combine(appDir, file); midiFile.Write(file); Process.Start(appDir); #if DEBUG var file2 = file + ".txt"; file2 = Path.Combine(appDir, file2); File.WriteAllText(file2, sb.ToString()); Process.Start(file2); #endif using (var outputDevice = OutputDevice.GetByName(nameSynth)) using (var playback = midiFile.GetPlayback(outputDevice)) { // playback.Speed = 2.0; playback.Play(); } }
/// <summary> /// Gets MIDI events sequence to switch to the specified General MIDI Level 2 program. /// </summary> /// <param name="program"><see cref="GeneralMidi2Program"/> to get events for.</param> /// <param name="channel">Channel events should be created for.</param> /// <returns>MIDI events sequence to switch to the <paramref name="program"/>.</returns> /// <exception cref="InvalidEnumArgumentException"><paramref name="program"/> specified an invalid value.</exception> public static IEnumerable <MidiEvent> GetProgramEvents(this GeneralMidi2Program program, FourBitNumber channel) { ThrowIfArgument.IsInvalidEnumValue(nameof(program), program); var programData = ProgramsData[program]; return(new[] { ControlName.BankSelect.GetControlChangeEvent(programData.BankMsb, channel), ControlName.LsbForBankSelect.GetControlChangeEvent(programData.BankLsb, channel), programData.GeneralMidiProgram.GetProgramEvent(channel) }); }
public void TryParse_InvalidFormat() { Assert.AreEqual(false, FourBitNumber.TryParse("sdsd", out _)); }
public void Parse() { Assert.AreEqual((FourBitNumber)12, FourBitNumber.Parse("12")); Assert.AreEqual((FourBitNumber)0, FourBitNumber.Parse("0")); Assert.AreEqual((FourBitNumber)15, FourBitNumber.Parse("15")); }
public void Parse_OutOfRange() { Assert.Throws <FormatException>(() => FourBitNumber.Parse("200")); Assert.Throws <FormatException>(() => FourBitNumber.Parse("16")); }
public void Parse_InvalidFormat() { Assert.Throws <FormatException>(() => FourBitNumber.Parse("sdsd")); }
public static byte Combine(FourBitNumber head, FourBitNumber tail) { return((byte)((head << 4) | tail)); }
public static byte TrackType(FourBitNumber channel) { return(TrackType((byte)channel)); }
/// <summary> /// Gets an instance of the <see cref="ControlChangeEvent"/> corresponding to the specified controller. /// </summary> /// <param name="controlName"><see cref="ControlName"/> to get an event for.</param> /// <param name="controlValue">Controller value to set to event.</param> /// <param name="channel">Channel an event should be created for.</param> /// <returns>An instance of the <see cref="ControlChangeEvent"/> corresponding to the <paramref name="controlName"/>.</returns> /// <exception cref="InvalidEnumArgumentException"><paramref name="controlName"/> specified an invalid value.</exception> public static ControlChangeEvent GetControlChangeEvent(this ControlName controlName, SevenBitNumber controlValue, FourBitNumber channel) { ThrowIfArgument.IsInvalidEnumValue(nameof(controlName), controlName); return(new ControlChangeEvent(controlName.AsSevenBitNumber(), controlValue) { Channel = channel }); }
public PatternContext(TempoMap tempoMap, FourBitNumber channel) { TempoMap = tempoMap; Channel = channel; }
/// <summary> /// Initializes a new instance of the <see cref="NoteId"/> class. /// </summary> /// <param name="channel">The audio channel associated with the musical note.</param> /// <param name="noteNumber">The identification number associated with the musical note.</param> public NoteId(FourBitNumber channel, SevenBitNumber noteNumber) { Channel = channel; NoteNumber = noteNumber; }