/// <summary> /// Ends the current recording session, returning a MIDI file /// </summary> /// <param name="trimRemainder">Indicates whether or not the silent remainder of the recording (if any) is trimmed</param> /// <returns>The MIDI file containing the recorded performance, or null if recording was never started.</returns> /// <remarks>The returned file is always a type 1 MIDI file at the stream's timebase, and following the stream's tempo. The file consists of two tracks. Track 0 is a meta track containing the tempo map, and the other track contains the performance data</remarks> public MidiFile EndRecording(bool trimRemainder = false) { if (IntPtr.Zero == _handle) { throw new InvalidOperationException("The device is closed."); } if (0 == _recordingLastTimestamp) { return(null); } var result = new MidiFile(1, unchecked ((short)_timeBase)); var tb = _timeBase; var mt = _microTempo; var pos = _recordingPos; var ts = _recordingLastTimestamp; Interlocked.Exchange(ref _recordingLastTimestamp, 0); Interlocked.Exchange(ref _recordingPos, 0); lock (_recordingTrack0Lock) { result.Tracks.Add(_recordingTrack0); Interlocked.Exchange(ref _recordingTrack0, null); } result.Tracks.Add(_recordingSequence); Interlocked.Exchange(ref _recordingSequence, null); var endTrack = new MidiSequence(); int len; if (!trimRemainder) { // we need to compute the number of MIDI ticks since // _recordingLastTimestamp (last message received) // first recompute our timing var ticksusec = mt / (double)tb; var tickspertick = ticksusec / (TimeSpan.TicksPerMillisecond / 1000) * 100; // now convert the time difference to MIDI ticks var remst = unchecked ((int)Math.Round((_PreciseUtcNowTicks - ts) / tickspertick, MidpointRounding.AwayFromZero)); // tack it on to the length len = pos + remst; } else { len = result.Tracks[1].Length; } endTrack.Events.Add(new MidiEvent(len, new MidiMessageMetaEndOfTrack())); result.Tracks[0] = MidiSequence.Merge(result.Tracks[0], endTrack); result.Tracks[1] = MidiSequence.Merge(result.Tracks[1], endTrack); return(result); }
/// <summary> /// Plays the file over the specified device /// </summary> /// <param name="deviceIndex">The index of the device to use</param> /// <param name="loop">Indicates whether to loop playback or not</param> public void Preview(int deviceIndex = 0, bool loop = false) { MidiSequence.Merge(Tracks).Preview(TimeBase, deviceIndex, loop); }
/// <summary> /// Plays the file over the specified device /// </summary> /// <param name="device">The MIDI output device to use</param> /// <param name="loop">Indicates whether to loop playback or not</param> public void Preview(MidiOutputDevice device = null, bool loop = false) { MidiSequence.Merge(Tracks).Preview(TimeBase, device, loop); }