private void MIDI(byte Cmd, byte Val1, byte Val2) { /* * Just a small note on the code for setting up a midi event: * You can use the VstEventCollection class (Framework) to setup one or more events * and then call the ToArray() method on the collection when passing it to * ProcessEvents. This will save you the hassle of dealing with arrays explicitly. * http://computermusicresource.com/MIDI.Commands.html * * Freq to Midi notes etc: * http://www.sengpielaudio.com/calculator-notenames.htm * * Example to use NAudio Midi support * http://stackoverflow.com/questions/6474388/naudio-and-midi-file-reading */ var midiData = new byte[4]; midiData[0] = Cmd; midiData[1] = Val1; midiData[2] = Val2; midiData[3] = 0; // Reserved, unused var vse = new VstMidiEvent(/*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); var ve = new VstEvent[1]; ve[0] = vse; PluginContext.PluginCommandStub.ProcessEvents(ve); }
public VstMidiEvent ProcessEvent(VstMidiEvent inEvent) { if (!MidiHelper.IsNoteOff(inEvent.Data) && !MidiHelper.IsNoteOn(inEvent.Data)) { return inEvent; } byte[] outData = new byte[4]; inEvent.Data.CopyTo(outData, 0); outData[2] += (byte)_gainMgr.CurrentValue; if (outData[2] > 127) { outData[2] = 127; } if (outData[2] < 0) { outData[2] = 0; } VstMidiEvent outEvent = new VstMidiEvent( inEvent.DeltaFrames, inEvent.NoteLength, inEvent.NoteOffset, outData, inEvent.Detune, inEvent.NoteOffVelocity); return outEvent; }
private void MIDI(byte Cmd,byte Val1,byte Val2) { byte[] midiData = new byte[4]; midiData[0] = Cmd; midiData[1] = Val1; midiData[2] = Val2; midiData[3] = 0; // Reserved, unused VstMidiEvent vse = new VstMidiEvent(/*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); VstEvent[] ve = new VstEvent[1]; ve[0] = vse; pluginContext.PluginCommandStub.ProcessEvents(ve); }
public void ProcessCurrentEvents() { if (CurrentEvents == null || CurrentEvents.Count == 0) { return; } // always expect some hosts not to support this. if (_midiHost != null) { VstEventCollection outEvents = new VstEventCollection(); // NOTE: other types of events could be in the collection! foreach (VstEvent evnt in CurrentEvents) { switch (evnt.EventType) { case VstEventTypes.MidiEvent: VstMidiEvent midiEvent = (VstMidiEvent)evnt; midiEvent = Gain.ProcessEvent(midiEvent); midiEvent = Transpose.ProcessEvent(midiEvent); outEvents.Add(midiEvent); break; default: // non VstMidiEvent outEvents.Add(evnt); break; } } _midiHost.Process(outEvents); } // Clear the cache, we've processed the events. CurrentEvents = null; }
/// <summary> /// Receives processed MssEvents from the IWetMssEventOutputPort. /// </summary> /// <param name="mssEvents">List of processed mss events</param> /// <param name="sampleTimeAtEndOfProcessingCycle"> /// If wetMssEventOutputPort is configured to only output when a processing cycle ends then /// sampleTimeAtEndOfProcessingCycle will contain the end time the cycle that just ended. /// </param> public void IWetMssEventOutputPort_SendingWetMssEvents(List <MssEvent> mssEvents, long sampleTimeAtEndOfProcessingCycle) { if (this.vstHost == null) { return; } // a plugin must implement IVstPluginMidiSource or this call will throw an exception. IVstMidiProcessor midiHost = this.vstHost.GetInstance <IVstMidiProcessor>(); // always expect some hosts not to support this. if (midiHost != null) { //Attempts to convert each MssEvent to a VstMidiEvent and add it to outEvents foreach (MssEvent mssEvent in mssEvents) { //This will return null if there is no valid conversion. VstMidiEvent midiEvent = ConvertMssEventToVstMidiEvent(mssEvent, this.SampleTimeAtStartOfProcessingCycle, this.hostInfoOutputPort.SampleRate); if (midiEvent != null) { this.outEvents.Add(midiEvent); //midiHost.Process(outEvents); //outEvents.Clear(); } } //TODO: Figure out why it doesn't work to send all of the events at once. //Sends VstMidiEvents to host midiHost.Process(outEvents); outEvents.Clear(); } OnProcessingCycleEnd(sampleTimeAtEndOfProcessingCycle); }
//*******************************Helpers******************************* //if testMssToMidi is true then this method tests ConvertMssEventToVstMidiEvent. Otherwise this method tests ConvertVstMidiEventToMssEvent protected void Test_MsgConversion(MssMsgType msgType, int midiChannel, int midiParam1, int midiParam2, bool testMssToMidi) { long sampleTimeAtStartOfCycle = 12345; int deltaFrames = 789; MidiHandlerProtectedWrapper midiHandler = Factory_MidiHandler_Basic(); MssEvent mssEvent = new MssEvent(); if (msgType == MssMsgType.PitchBend) { mssEvent.mssMsg = new MssMsg(msgType, midiChannel, MssMsgUtil.UNUSED_MSS_MSG_DATA, (midiParam2 << 7) + midiParam1); } else { mssEvent.mssMsg = new MssMsg(msgType, midiChannel, midiParam1, midiParam2); } mssEvent.sampleTime = sampleTimeAtStartOfCycle + deltaFrames; byte[] midiData = MidiUtil.CreateMidiData(msgType, midiChannel, (byte)midiParam1, (byte)midiParam2); VstMidiEvent midiEvent = new VstMidiEvent(deltaFrames, 0, 0, midiData, 0, 0x00); if (testMssToMidi == true) { MssEvent convertedMssEvent = midiHandler.ConvertVstMidiEventToMssEventWrapper( midiEvent, sampleTimeAtStartOfCycle, this.hostInfoOutputPort.SampleRate); Assert.AreEqual(mssEvent, convertedMssEvent); } else { VstMidiEvent ConvertedMidiEvent = midiHandler.ConvertMssEventToVstMidiEventWrapper( mssEvent, sampleTimeAtStartOfCycle, this.hostInfoOutputPort.SampleRate); Assert.AreEqual(midiEvent.Data, ConvertedMidiEvent.Data); Assert.AreEqual(midiEvent.DeltaFrames, ConvertedMidiEvent.DeltaFrames); } }
public void Test_VstMidiEvent_Constructor() { int deltaFrames = 12; int noteLength = 100; int noteOffset = 1; byte[] midiData = new byte[] { 0x9C, 0x7F, 0x40 }; short detune = -24; byte noteOffVelocity = 64; VstMidiEvent me = new VstMidiEvent(deltaFrames, noteLength, noteOffset, midiData, detune, noteOffVelocity); Assert.AreEqual(VstEventTypes.MidiEvent, me.EventType, "VstMidiEvent.EventType"); Assert.AreEqual(deltaFrames, me.DeltaFrames, "VstMidiEvent.DeltaFrames"); Assert.AreEqual(noteLength, me.NoteLength, "VstMidiEvent.NoteLength"); Assert.AreEqual(noteOffset, me.NoteOffset, "VstMidiEvent.NoteOffset"); Assert.IsNotNull(me.Data, "VstMidiEvent.Data is null"); Assert.AreEqual(3, me.Data.Length, "VstMidiEvent.Data.Length"); Assert.AreEqual(0x9C, me.Data[0], "VstMidiEvent.Data[0]"); Assert.AreEqual(0x7F, me.Data[1], "VstMidiEvent.Data[1]"); Assert.AreEqual(0x40, me.Data[2], "VstMidiEvent.Data[2]"); Assert.AreEqual(detune, me.Detune, "VstMidiEvent.Detune"); Assert.AreEqual(noteOffVelocity, me.NoteOffVelocity, "VstMidiEvent.NoteOffVelocity"); }
public void Test_VstMidiEvent_Constructor() { int deltaFrames = 12; int noteLength = 100; int noteOffset = 1; byte[] midiData = new byte[] { 0x9C, 0x7F, 0x40 }; short detune = -24; byte noteOffVelocity = 64; var me = new VstMidiEvent(deltaFrames, noteLength, noteOffset, midiData, detune, noteOffVelocity); me.EventType.Should().Be(VstEventTypes.MidiEvent); me.DeltaFrames.Should().Be(deltaFrames); me.NoteLength.Should().Be(noteLength); me.NoteOffset.Should().Be(noteOffset); me.Data.Should().NotBeNull(); me.Data.Length.Should().Be(midiData.Length); me.Data[0].Should().Be(midiData[0]); me.Data[1].Should().Be(midiData[1]); me.Data[2].Should().Be(midiData[2]); me.Detune.Should().Be(detune); me.NoteOffVelocity.Should().Be(noteOffVelocity); }
private void MIDI(byte Cmd, byte Val1, byte Val2, int deltaFrames = 0) { /* * Just a small note on the code for setting up a midi event: * You can use the VstEventCollection class (Framework) to setup one or more events * and then call the ToArray() method on the collection when passing it to * ProcessEvents. This will save you the hassle of dealing with arrays explicitly. * http://computermusicresource.com/MIDI.Commands.html * * Freq to Midi notes etc: * http://www.sengpielaudio.com/calculator-notenames.htm * * Example to use NAudio Midi support * http://stackoverflow.com/questions/6474388/naudio-and-midi-file-reading */ var midiData = new byte[4]; midiData[0] = Cmd; midiData[1] = Val1; midiData[2] = Val2; midiData[3] = 0; // Reserved, unused var vse = new VstMidiEvent(deltaFrames, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); var ve = new VstEvent[1]; ve[0] = vse; PluginContext.PluginCommandStub.ProcessEvents(ve); }
// Process the incoming VST events. *** This is the core of the VST right here. *** public void Process(VstEventCollection inputEvents) { if (_plugin == null) return; _plugin.callCount++; bool thrudone = false; foreach (VstEvent evnt in inputEvents) { _plugin.eventCount++; // Skip non-MIDI Events if (evnt.EventType != VstEventTypes.MidiEvent) { continue; } _plugin.midiCount++; // If set in options, keep the original event as well if (_plugin.Options.MidiThruAll) { Events.Add(evnt); thrudone = true; } // Don't do any more if we aren't running. if (_plugin.CurrentMode != Constants.Modes.RUN) continue; // Construct a MIDI event and act on it VstMidiEvent midiInputEvent = (VstMidiEvent)evnt; byte command = (byte)(midiInputEvent.Data[0] & 0xF0); byte channel = (byte)(midiInputEvent.Data[0] & 0x0F); byte note = midiInputEvent.Data[1]; byte velocity = midiInputEvent.Data[2]; MapNoteItem map = _plugin.NoteMaps[note]; byte[] midiData = null; // Filter out everything except Note On/Note Off and CC events switch (command) { case 0x90: // Note On map.Triggered(Constants.MapTypes.ON); if (map.isDefined(Constants.MapTypes.ON)) { _plugin.hitCount++; midiData = MapNoteItem.StringToBytes(map.OutputBytesStringOn, channel, velocity); } break; case 0x80: // Note Off map.Triggered(Constants.MapTypes.OFF); if (map.isDefined(Constants.MapTypes.OFF)) { _plugin.hitCount++; midiData = MapNoteItem.StringToBytes(map.OutputBytesStringOff, channel, velocity); } break; case 0xB0: // Continuous Controller map.Triggered(Constants.MapTypes.CC); if (map.isDefined(Constants.MapTypes.CC)) { _plugin.hitCount++; midiData = MapNoteItem.StringToBytes(map.OutputBytesStringCC, channel, velocity); } break; default: // Ignore everything else, but keep going below break; } // Check that we got a result. If not - no match. if (midiData == null) { if (_plugin.Options.MidiThru) { // add original event, if not added already. if (!thrudone) { Events.Add(evnt); } } continue; } // In most cases, use VstMidiSysExEvent in place of VstMidiEvent, since this seems to allow arbitary bytes. if (_plugin.Options.AlwaysSysEx) { VstMidiSysExEvent mappedEvent = new VstMidiSysExEvent(midiInputEvent.DeltaFrames, midiData); Events.Add(mappedEvent); } else // Ugly! Split message into three-byte chunks and send them all. { List<byte[]> midichunks = new List<byte[]>(); for (int i = 0; i < midiData.Length; i += 3) { midichunks.Add(midiData.Skip(i).Take(3).ToArray()); } foreach (byte[] midi in midichunks) { VstMidiEvent mappedEvent = new VstMidiEvent(midiInputEvent.DeltaFrames, midiInputEvent.NoteLength, midiInputEvent.NoteOffset, midi, midiInputEvent.Detune, midiInputEvent.NoteOffVelocity); Events.Add(mappedEvent); } } } // foreach }
public MssEvent ConvertVstMidiEventToMssEventWrapper(VstMidiEvent midiEvent, long processingCycleStartTime, double sampleRate) { return ConvertVstMidiEventToMssEvent(midiEvent, processingCycleStartTime, sampleRate); }
public void AddMidiEvent(VstMidiEvent evt) { lstEvent.Add(evt); }
// Process the incoming VST events. This is the core of the app right here. !!!! public void Process(VstEventCollection inputEvents) { _plugin.callCount++; foreach (VstEvent evnt in inputEvents) { _plugin.eventCount++; // Skip non-MIDI Events if (evnt.EventType != VstEventTypes.MidiEvent) { continue; } _plugin.midiCount++; VstMidiEvent midiInputEvent = (VstMidiEvent)evnt; // Filter out everything except Note On/Note Off events byte midiCommand = (byte)(midiInputEvent.Data[0] & 0xF0); if ((midiCommand == 0x90) || (midiCommand == 0x80)) { byte triggerNoteNum = midiInputEvent.Data[1]; if (_plugin.NoteMap.Contains(triggerNoteNum)) { _plugin.hitCount++; byte channel = (byte)(midiInputEvent.Data[0] & 0x0F); byte velocity = midiInputEvent.Data[2]; MapNoteItem item = _plugin.NoteMap[triggerNoteNum]; byte[] midiData = null; if (midiCommand == 0x90) { midiData = MapNoteItem.StringToBytes(item.OutputBytesStringOn, channel, velocity); } else if (midiCommand == 0x80) { midiData = MapNoteItem.StringToBytes(item.OutputBytesStringOff, channel, velocity); } // else midiData remains null, which should never happen // If OutputBytes was empty, ignore this event. Could try sending the event with an empty array (not null) - not sure what would happen. if (midiData == null) { continue; } // Trick: Use VstMidiSysExEvent in place of VstMidiEvent, since this seems to allow arbitary bytes. VstMidiSysExEvent mappedEvent = new VstMidiSysExEvent(midiInputEvent.DeltaFrames, midiData); Events.Add(mappedEvent); } else if (_plugin.midiThru) { // add original event Events.Add(evnt); } // Otherwise ignore silently } } }
public void OrderNoteOnEventsWithOctaves() { // mindegyik Note On eventből csak egy legyen (az AddOctaves() miatt kell) List <VstMidiEvent> distinctList = makeCopy(_octavesAddedOrderedNoteOnEvents); distinctList = distinctList.GroupBy(e => e.Data[1]) .Select(grp => grp.First()) .ToList(); switch (Direction) { case Directions.up: _octavesAddedOrderedNoteOnEvents = distinctList.OrderBy(midiEvent => midiEvent.Data[1]).ToList(); break; case Directions.down: _octavesAddedOrderedNoteOnEvents = distinctList.OrderByDescending(midiEvent => midiEvent.Data[1]).ToList(); break; case Directions.updown: _octavesAddedOrderedNoteOnEvents = distinctList.OrderBy(midiEvent => midiEvent.Data[1]).ToList(); List <VstMidiEvent> descendingList = distinctList.OrderByDescending(midiEvent => midiEvent.Data[1]).ToList(); if (descendingList.Count != 0) { descendingList.RemoveAt(0); // first item } if (descendingList.Count != 0) { descendingList.RemoveAt(descendingList.Count - 1); // last item } _octavesAddedOrderedNoteOnEvents.AddRange(descendingList); break; case Directions.downup: _octavesAddedOrderedNoteOnEvents = distinctList.OrderByDescending(midiEvent => midiEvent.Data[1]).ToList(); List <VstMidiEvent> ascendingList = distinctList.OrderBy(midiEvent => midiEvent.Data[1]).ToList(); if (ascendingList.Count != 0) { ascendingList.RemoveAt(0); // first item } if (ascendingList.Count != 0) { ascendingList.RemoveAt(ascendingList.Count - 1); // last item } _octavesAddedOrderedNoteOnEvents.AddRange(ascendingList); break; case Directions.random: Random rand = new Random(); _octavesAddedOrderedNoteOnEvents = distinctList.ToList(); int n = _octavesAddedOrderedNoteOnEvents.Count; while (n > 1) { n--; int k = rand.Next(n + 1); VstMidiEvent e = _octavesAddedOrderedNoteOnEvents[k]; _octavesAddedOrderedNoteOnEvents[k] = distinctList[n]; _octavesAddedOrderedNoteOnEvents[n] = e; } break; default: break; } }
private VstEvent[] filterMidiInMessages(int midiInCount, VstInstrumentPlugin plugin) { //bool active, int lowerNote, int upperNote, int transpose, ControlPedalAction pedal) //, ch.KeyZoneLower, ch.KeyZoneUpper, ch.Transpose, ch.ControlPedalAction int pitch; mFilteredMidiEvents.Clear(); bool wrongChannel = false; for (int i = 0; i < midiInCount; i++) { MidiMessage msg = mMidiInMessages[i]; wrongChannel = ((msg.Channel + 1) != (int)plugin.MidiChannel) && (plugin.MidiChannel != MidiChannel.ChannelAll); // Add note to selection // Copy event byte[] data = new byte[4]; msg.Data.CopyTo(data, 0); VstMidiEvent newEv = new VstMidiEvent( /*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, data, /*Detune*/ 0, /*NoteOffVelocity*/ 127); // Force to midi channel 1 = 0xn0 data[0] = (byte)(data[0] & 0xf0); if (data[0] == 176 && data[1] == 11) { switch (plugin.ExpressionPedalFunction) { case ExpressionPedalFunction.EffectControl: // Re-route foot control to wheel! data[1] = 1; if (plugin.UseExtendedEffectRange) { int wheel = data[2] * 2; if (wheel > 255) { wheel = 255; } // Most plugins use an inverted direction. So default is to invert. // If ExpressionPedalInvert; do not invert data if (plugin.ExpressionPedalInvert) { data[2] = (byte)wheel; } else { data[2] = (byte)(255 - wheel); } } else { // Most plugins use an inverted direction. So default is to invert. // If ExpressionPedalInvert; do not invert data if (!plugin.ExpressionPedalInvert) { data[2] = (byte)(127 - data[2]); } } break; case ExpressionPedalFunction.VolumeControl: // Do nothing; break; case ExpressionPedalFunction.None: // Next for; do not handle this midi command continue; default: // Do nothing break; } } if (msg.IsNoteOn(out pitch)) { // Note-on event if (wrongChannel || (plugin.State != PluginState.Activated || plugin.KeyZoneActive && (pitch < plugin.KeyZoneLower || pitch > plugin.KeyZoneUpper))) { // Ignore note-on continue; } plugin.Notes[pitch].Pressed = true; plugin.Notes[pitch].Velocity = data[2]; newEv.Data[1] += (byte)plugin.Transpose; mFilteredMidiEvents.Add(newEv); } else if (msg.IsNoteOff(out pitch)) { // Note-off event if (wrongChannel || (plugin.KeyZoneActive && (pitch < plugin.KeyZoneLower || pitch > plugin.KeyZoneUpper))) { // Ignore note-off continue; } newEv.Data[1] += (byte)plugin.Transpose; if (plugin.Notes[pitch].PressedTime >= plugin.NoteDropDelay) { // Also send note-off message for note-dropped note byte[] noteOffData = new byte[4]; noteOffData[0] = 128; noteOffData[1] = (byte)(pitch - 12); noteOffData[2] = plugin.Notes[pitch].Velocity; noteOffData[3] = 112; VstMidiEvent noteOffEvent = new VstMidiEvent( /*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, noteOffData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); mFilteredMidiEvents.Add(noteOffEvent); } plugin.Notes[pitch].Pressed = false; mFilteredMidiEvents.Add(newEv); } else if (msg.IsSustain()) { if (plugin.SustainEnabled) { mFilteredMidiEvents.Add(newEv); } continue; } else { // All other events mFilteredMidiEvents.Add(newEv); } } // Process note on times; for now only required when NoteDrop = true if (plugin.NoteDrop) { for (int i = 0; i < 255; i++) { if (plugin.Notes[i].Pressed) { plugin.Notes[i].PressedTime++; if (plugin.Notes[i].PressedTime == plugin.NoteDropDelay) { byte[] noteDropData = new byte[4]; noteDropData[0] = 144; noteDropData[1] = (byte)(i - 12); noteDropData[2] = plugin.Notes[i].Velocity; noteDropData[3] = 112; VstMidiEvent newEv = new VstMidiEvent( /*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, noteDropData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); mFilteredMidiEvents.Add(newEv); } } } } return(mFilteredMidiEvents.ToArray()); }
/// <summary> /// Attempts to create a VstMidiEvent representation of <paramref name="mssEvent"/>. /// </summary> /// <returns>The VstMidiEvent representation of mssEvent or null of there is no valid conversion.</returns> protected static VstMidiEvent ConvertMssEventToVstMidiEvent(MssEvent mssEvent, long sampleTimeAtStartOfProcessingCycle, double sampleRate) { Debug.Assert(mssEvent.sampleTime >= sampleTimeAtStartOfProcessingCycle); //Calculate delta frames int deltaFrames = (int)(mssEvent.sampleTime - sampleTimeAtStartOfProcessingCycle); byte[] midiData = new byte[3]; //Get status half of first byte. byte statusByte; if (MidiUtil.GetStatusFromMssMsgType(mssEvent.mssMsg.Type, out statusByte) == false) { return null; } //subtract 1 becasue channels are 0 based in midi but 1 based in mss byte channelByte = (byte)(mssEvent.mssMsg.Data1AsInt - 1); midiData[0] = (byte) (statusByte | channelByte); if (mssEvent.mssMsg.Type == MssMsgType.PitchBend) { //most significant bits int MsbVal = (mssEvent.mssMsg.Data3AsInt) >> 7; midiData[2] = (byte)MsbVal; midiData[1] = (byte)((mssEvent.mssMsg.Data3AsInt) - (MsbVal << 7)); } else if (mssEvent.mssMsg.Type == MssMsgType.ChanAftertouch) { midiData[1] = (byte)mssEvent.mssMsg.Data3AsInt; midiData[2] = 0; } else { midiData[1] = (byte)mssEvent.mssMsg.Data2AsInt; midiData[2] = (byte)mssEvent.mssMsg.Data3AsInt; } VstMidiEvent midiEvent = new VstMidiEvent(deltaFrames, 0, 0, midiData, 0, 0); return midiEvent; }
public void ProcessCurrentEvents() { if (CurrentEvents == null || CurrentEvents.Count == 0) { return; } // a plugin must implement IVstPluginMidiSource or this call will throw an exception. IVstMidiProcessor midiHost = _plugin.Host.GetInstance <IVstMidiProcessor>(); // always expect some hosts not to support this. if (midiHost != null) { VstEventCollection outEvents = new VstEventCollection(); // NOTE: other types of events could be in the collection! foreach (VstEvent evnt in CurrentEvents) { switch (evnt.EventType) { case VstEventTypes.MidiEvent: VstMidiEvent midiEvent = (VstMidiEvent)evnt; //General midi effects for all inputs midiEvent = Gain.ProcessEvent(midiEvent); midiEvent = Transpose.ProcessEvent(midiEvent); //Process Midi Note in SampleManager if ((midiEvent.Data[0] & 0xF0) == 0x80) { _plugin.SampleManager.ProcessNoteOffEvent(midiEvent.Data[1]); } if ((midiEvent.Data[0] & 0xF0) == 0x90) { // note on with velocity = 0 is a note off if (MidiHelper.IsNoteOff(midiEvent.Data)) { _plugin.SampleManager.ProcessNoteOffEvent(midiEvent.Data[1]); } else { _plugin.SampleManager.ProcessNoteOnEvent(midiEvent.Data[1]); } } outEvents.Add(midiEvent); break; default: // non VstMidiEvent outEvents.Add(evnt); break; } } midiHost.Process(outEvents); } // Clear the cache, we've processed the events. CurrentEvents = null; }
// deep copy (reference type) private VstMidiEvent makeCopy(VstMidiEvent e) { VstMidiEvent newEvent = new VstMidiEvent(e.DeltaFrames, e.NoteLength, e.NoteOffset, e.Data, e.Detune, e.NoteOffVelocity); return(newEvent); }
private IEnumerable <VstEvent> CreateCascadeNotes(VstMidiEvent inEvent, int quartersPassed, VstTimeInfo timeInfo) { //Log("CreateCascadeNotes"); var origNote = inEvent.Data[1] % 12; //Log("origNote" + origNote); var step = Array.IndexOf(A_MINOR_MIDI, origNote); var note = inEvent.Data[1]; if (step == -1) { //Log("rounding"); note++; //rounding into scale step = Array.IndexOf(A_MINOR_MIDI, (origNote + 1) % 12); } var upDown = CascadeMgr.CurrentValue > 0.5 ? 1 : -1; //Log("doing " + note + " " + quartersPassed); for (int x = 0; x < quartersPassed; x++) { //Log("stepping " + MINOR[step]); //todo: up or down note += (byte)(MINOR[upDown == 1 ? step : ((step + 6) % 7)] * upDown); step = (step + 7 + upDown) % 7; } var name = NAMES[note % 12]; Log("step" + name); var delta = (int)(TimeInfos[inEvent.Data[1]].SamplePosition + spb * quartersPassed - timeInfo.SamplePosition); Log("delta " + delta); //outData[1] pitch //outData[2] volume var outDataOn = new byte[] { 0x90, note, inEvent.Data[2], 0 }; var outEventOn = new VstMidiEvent( delta, 0, 0, outDataOn, 0, 0); var outDataOff = new byte[] { 0x80, note, 0, 0 }; var outEventOff = new VstMidiEvent( delta + (int)spb, // quarter length 0, 0, outDataOff, 0, 0); return(new VstEvent[] { outEventOn, outEventOff }); }
public void Process(VstEventCollection events) { foreach (VstEvent evnt in events) { if (evnt.EventType != VstEventTypes.MidiEvent) { continue; } VstMidiEvent midiEvent = (VstMidiEvent)evnt; // note on if ((midiEvent.Data[0] & 0xF0) == 0x90) { // note off // You can treat note-on midi events with a velocity of 0 (zero) as a note-off midi event. if (midiEvent.Data[2] == 0) { lock (((ICollection)NoteOffNumbers).SyncRoot) { lock (((ICollection)_noteOnEvents).SyncRoot) { lock (((ICollection)_octavesAddedOrderedNoteOnEvents).SyncRoot) { NoteOffNumbers.Enqueue(midiEvent.Data[1]); _noteOnEvents.RemoveAll(n => n.Data[1] == midiEvent.Data[1]); AddOctaves(); OrderNoteOnEventsWithOctaves(); } } } } // note on else { lock (((ICollection)NoteOnNumbers).SyncRoot) { lock (((ICollection)_noteOnEvents).SyncRoot) { lock (((ICollection)_octavesAddedOrderedNoteOnEvents).SyncRoot) { NoteOnNumbers.Enqueue(midiEvent.Data[1]); _noteOnEvents.Add(midiEvent); AddOctaves(); OrderNoteOnEventsWithOctaves(); } } } } } // note off else if ((midiEvent.Data[0] & 0xF0) == 0x80) { lock (((ICollection)NoteOffNumbers).SyncRoot) { lock (((ICollection)_noteOnEvents).SyncRoot) { lock (((ICollection)_octavesAddedOrderedNoteOnEvents).SyncRoot) { NoteOffNumbers.Enqueue(midiEvent.Data[1]); /* FOR TESTING ADDOCTAVES() * string notes = ""; * foreach (VstMidiEvent e in _noteOnEvents) * notes += e.Data[1] + " "; * * MessageBox.Show("Process method: \nNoteOnEvents: " + notes); */ _noteOnEvents.RemoveAll(n => n.Data[1] == midiEvent.Data[1]); AddOctaves(); OrderNoteOnEventsWithOctaves(); } } } } } }
public MidiMessage(VstMidiEvent vstMidiEvent) { _vstMidiEvent = vstMidiEvent; }
public void SetMidiEvent(int deltaFrames, byte[] msg) { if (FCanEvents) { VstEvent evt = new VstMidiEvent(deltaFrames, 0, 0, msg, 0, 0); MidiEvents.Add(evt); FHasEvents = true; } }
/// <summary> /// Attempts to create an MssEvent representation of <paramref name="midiEvent"/>. /// </summary> /// <returns>The MssEvent representation of midiEvent or null of there is no valid conversion.</returns> protected static MssEvent ConvertVstMidiEventToMssEvent(VstMidiEvent midiEvent, long sampleTimeAtStartOfProcessingCycle, double sampleRate) { MssEvent mssEvent = new MssEvent(); //Sets the sample time for mssEvent. mssEvent.sampleTime = sampleTimeAtStartOfProcessingCycle + midiEvent.DeltaFrames; MssMsgType msgType = MidiUtil.GetMssTypeFromMidiData(midiEvent.Data); mssEvent.mssMsg.Type = msgType; //If msgType is "Unsupported" then midiEvent cannot be represented as an MssEvent if (msgType == MssMsgType.Unsupported) { return null; } //Sets mssEvent's Data1 (midi channel). //Adds one because channels in an MssMsg start at 1 but channels in a VstMidiEvent start at 0 mssEvent.mssMsg.Data1 = (midiEvent.Data[0] & 0x0F) + 1; //Sets mssEvent's Data2 and Data3 (the midi message's data bytes). if (msgType == MssMsgType.PitchBend) { //The two data bytes for pitch bend are used to store one 14-bit number so this number is stored in //mssEvent.Data3 and mssEvent.Data2 is not used. mssEvent.mssMsg.Data2 = MssMsgUtil.UNUSED_MSS_MSG_DATA; //data1 contains the least significant 7 bits of the pitch bend value and data2 contains the most //significant 7 bits mssEvent.mssMsg.Data3 = (midiEvent.Data[2] << 7) + midiEvent.Data[1]; } else if (msgType == MssMsgType.ChanAftertouch) { mssEvent.mssMsg.Data2 = MssMsgUtil.UNUSED_MSS_MSG_DATA; mssEvent.mssMsg.Data3 = midiEvent.Data[1]; } else { mssEvent.mssMsg.Data2 = midiEvent.Data[1]; mssEvent.mssMsg.Data3 = midiEvent.Data[2]; } return mssEvent; }
// 44100 sample frame = 1 sec // az_octavesAddedOrderedNoteOnEventset dolgozza fel public void Arpeggiate() { countQuarter(); // if new Tempo was set VstMidiEvent newMidiEvent; if (_octavesAddedOrderedNoteOnEvents.Count == 0) { _rythmCounter = 0; } if (_processedFrames == 0 && _octavesAddedOrderedNoteOnEvents.Count > 0) // kör eleje, van lejátszandó hang { _actualMidiEvent = makeCopy(_octavesAddedOrderedNoteOnEvents[_counter]); // probability randomValue = random.Next(1, 101); // 1-100 if (_rythm[_rythmCounter].note && randomValue <= Probability) // ha nem szünet { byte[] midiData = new byte[4]; midiData[0] = 0x90; midiData[1] = _actualMidiEvent.Data[1]; if (_rythm[_rythmCounter].accent) { midiData[2] = 0x7F; } else { midiData[2] = _actualMidiEvent.Data[2]; } midiData[3] = 0; newMidiEvent = new VstMidiEvent(_remainder, _actualMidiEvent.NoteLength, _actualMidiEvent.NoteOffset, midiData, _actualMidiEvent.Detune, _actualMidiEvent.NoteOffVelocity); Events.Add(newMidiEvent); _processedFrames += 512; } else // ha szünet { _processedFrames += 512; } } // ha a még legalább egy kör van hátra addig, amíg a hangot ki kell játszani else if (_processedFrames < _rythm[_rythmCounter].frames - 512 && _actualMidiEvent != null) // kör léptetése { _processedFrames += 512; } else if (_actualMidiEvent != null) // note off. a processedFrames belépett a kritikus szakaszba { // && randomValue <= Probability if (_rythm[_rythmCounter].note) // ha nem szünet, akkor note off az előző hangra { // create note off event byte[] midiData = new byte[4]; midiData[0] = 0x80; midiData[1] = _actualMidiEvent.Data[1]; midiData[2] = _actualMidiEvent.Data[2]; midiData[3] = 0; newMidiEvent = new VstMidiEvent(Convert.ToInt32(_rythm[_rythmCounter].frames) - _processedFrames, _actualMidiEvent.NoteLength, _actualMidiEvent.NoteOffset, midiData, _actualMidiEvent.Detune, _actualMidiEvent.NoteOffVelocity); Events.Add(newMidiEvent); } if (_counter + 1 < _octavesAddedOrderedNoteOnEvents.Count) // note on a következő hangra az _octavesAddedOrderedNoteOnEvents listából { // rythm if (_rythm[_rythmCounter].note) // ha nem szünet volt, akkor lépthethetem az events listát. a probability itt nem érdekes { _counter++; } if ((_rythmCounter + 1) < _rythm.Count) { _rythmCounter++; } else { _rythmCounter = 0; _counter = 0; // ha a ritmusképlet körbeért, a hangok is kezdődjenek elölről } _actualMidiEvent = makeCopy(_octavesAddedOrderedNoteOnEvents[_counter]); randomValue = random.Next(1, 101); // következő hang if (_rythm[_rythmCounter].note && randomValue <= Probability) // ha nem szünet, jöhet a következő hang note on-ja is, a note off-fal egyidőben { // note on byte[] midiData = new byte[4]; midiData[0] = 0x90; midiData[1] = _actualMidiEvent.Data[1]; if (_rythm[_rythmCounter].accent) { midiData[2] = 0x7F; } else { midiData[2] = _actualMidiEvent.Data[2]; } midiData[3] = 0; newMidiEvent = new VstMidiEvent(Convert.ToInt32(_rythm[_rythmCounter].frames) - _processedFrames, _actualMidiEvent.NoteLength, _actualMidiEvent.NoteOffset, midiData, _actualMidiEvent.Detune, _actualMidiEvent.NoteOffVelocity); Events.Add(newMidiEvent); _remainder = 512 - (Convert.ToInt32(_rythm[_rythmCounter].frames) - _processedFrames); _processedFrames = 0; } else // ha a következő hang szünet { _remainder = 512 - (Convert.ToInt32(_rythm[_rythmCounter].frames) - _processedFrames); _processedFrames = 0; } } else // végigért az _octavesAddedOrderedNoteOnEvents listán, kör eleje { _counter = 0; _actualMidiEvent = null; _remainder = 0; _processedFrames = 0; // rythm if ((_rythmCounter + 1) < _rythm.Count) { _rythmCounter++; } else { _rythmCounter = 0; _counter = 0; // ha a ritmusképlet körbeért, a hangok is kezdődjenek elölről } } } }
void midiIn_MessageReceived(object sender, MidiInMessageEventArgs e) { progressLog1.LogMessage(Color.Blue, String.Format("Time {0} Message 0x{1:X8} Event {2}", e.Timestamp, e.RawMessage, e.MidiEvent)); //SendMidiOutMessage(e.MidiEvent); if (VSTForm.vst != null) { MidiEvent midiEvent = e.MidiEvent; byte[] midiData = { 0, 0, 0 }; if (midiEvent is NAudio.Midi.NoteEvent) { var me = (NAudio.Midi.NoteEvent) midiEvent; midiData = new byte[] { 0x90, // Cmd (byte) me.NoteNumber, // Val 1 (byte) me.Velocity, // Val 2 }; } else if (midiEvent is NAudio.Midi.ControlChangeEvent) { var cce = (NAudio.Midi.ControlChangeEvent) midiEvent; midiData = new byte[] { 0xB0, // Cmd (byte)cce.Controller, // Val 1 (byte)cce.ControllerValue, // Val 2 }; } else if (midiEvent is NAudio.Midi.PitchWheelChangeEvent) { // Pitch Wheel Value 0 is minimum, 0x2000 (8192) is default, 0x4000 (16384) is maximum NAudio.Midi.PitchWheelChangeEvent pe = (PitchWheelChangeEvent) midiEvent; midiData = new byte[] { 0xE0, // Cmd (byte)(pe.Pitch & 0x7f), // Val 1 (byte)((pe.Pitch >> 7) & 0x7f), // Val 2 }; } progressLog1.LogMessage(Color.Chocolate, String.Format("Sending mididata 0x00{0:X2}{1:X2}{2:X2}", midiData[2], midiData[1], midiData[0])); var vse = new VstMidiEvent(/*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 0); var ve = new VstEvent[1]; ve[0] = vse; VSTForm.vst.pluginContext.PluginCommandStub.ProcessEvents(ve); } }
private VstEvent[] CreateMidiEvent(byte statusByte, byte midiNote, byte midiVelocity) { /* * Just a small note on the code for setting up a midi event: * You can use the VstEventCollection class (Framework) to setup one or more events * and then call the ToArray() method on the collection when passing it to * ProcessEvents. This will save you the hassle of dealing with arrays explicitly. * http://computermusicresource.com/MIDI.Commands.html * * Freq to Midi notes etc: * http://www.sengpielaudio.com/calculator-notenames.htm * * Example to use NAudio Midi support * http://stackoverflow.com/questions/6474388/naudio-and-midi-file-reading */ byte[] midiData = new byte[4]; midiData[0] = statusByte; midiData[1] = midiNote; // Midi note midiData[2] = midiVelocity; // Note strike velocity midiData[3] = 0; // Reserved, unused VstMidiEvent vse = new VstMidiEvent(/*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); // previously 0 VstEvent[] ve = new VstEvent[1]; ve[0] = vse; return ve; }
/// <summary> /// Constructor /// </summary> /// <param name="settingsMgr"></param> /// <param name="channels"></param> public AudioPluginEngine(SettingsManager settingsMgr, VuMeter[] meters, Panel hostScrollPanel) { // Add editor panel to host to allow scrolling mHostScrollPanel = hostScrollPanel; Panel hostEditorPanel = new Panel(); hostScrollPanel.Controls.Add(hostEditorPanel); PluginChannels = new VstPluginChannel[NrOfPluginChannels]; mMidiPanic = new bool[NrOfPluginChannels]; // Create all channel, effect and master effect plugins for (int i = 0; i < NrOfPluginChannels; i++) { PluginChannels[i] = new VstPluginChannel(settingsMgr.Settings.AsioBufferSize); mMidiPanic[i] = false; } MasterEffectPluginChannel = new VstPluginChannel(settingsMgr.Settings.AsioBufferSize); foreach (VstPlugin plugin in PluginChannels.SelectMany(x => x.AllPlugins)) { plugin.EditorPanel = hostEditorPanel; // Let controls know if other control loaded an editor plugin.OnEditorOpening += chCtrl_OnEditorOpen; plugin.OnEditorOpened += chCtrl_OnEditorOpened; plugin.OnEditorClosed += chCtrl_OnEditorClose; } mSettingsMgr = settingsMgr; mVUMeters = meters; if (mSettingsMgr.Settings.VSTPluginFolders != null) { foreach (string path in mSettingsMgr.Settings.VSTPluginFolders) { addPath(path); } } MasterPan = mSettingsMgr.Settings.MasterPan; // Send all notes off on midi channel 1 byte[] midiData = new byte[4]; // http://www.midi.org/techspecs/midimessages.php midiData[0] = 176; // Send all notes off on midi channel 1 midiData[1] = 123; // All Notes Off midiData[2] = 0; midiData[3] = 0; VstMidiEvent midiPanicEvent = new VstMidiEvent( /*DeltaFrames*/ 0, /*NoteLength*/ 0, /*NoteOffset*/ 0, midiData, /*Detune*/ 0, /*NoteOffVelocity*/ 127); mMidiPanicEvents = new VstEvent[1]; mMidiPanicEvents[0] = midiPanicEvent; mMidiDevice = new MidiDevice(); }
public MssEvent ConvertVstMidiEventToMssEventWrapper(VstMidiEvent midiEvent, long processingCycleStartTime, double sampleRate) { return(ConvertVstMidiEventToMssEvent(midiEvent, processingCycleStartTime, sampleRate)); }