//See IDryMssEventInputPort public void ReceiveDryMssEvent(MssEvent mssEvent) { if (DryMssEventRecieved != null) { DryMssEventRecieved(mssEvent); } }
/// <summary> /// Midi events are received from the host on this method and are either send to the DryMssEventRelay or /// stored internally. /// </summary> /// <param name="events">A collection with midi events. Never null.</param> /// <remarks> /// Note that some hosts will only receieve midi events during audio processing. /// See also <see cref="IVstPluginAudioProcessor"/>. /// </remarks> public void Process(VstEventCollection vstEvents) { if (vstEvents == null || vstEvents.Count == 0 || this.vstHost == null) { return; } // NOTE: other types of events could be in the collection! foreach (VstEvent evnt in vstEvents) { if (evnt.EventType == VstEventTypes.MidiEvent) { VstMidiEvent midiEvent = (VstMidiEvent)evnt; MssEvent mssEvent = ConvertVstMidiEventToMssEvent(midiEvent, this.SampleTimeAtStartOfProcessingCycle, this.hostInfoOutputPort.SampleRate); if (mssEvent == null) { outEvents.Add(evnt); } else { this.dryMssEventInputPort.ReceiveDryMssEvent(mssEvent); } } else { // non VstMidiEvent outEvents.Add(evnt); } } }
/// <summary> /// Listens for GeneratorToggle messages /// </summary> protected void WetMssEventOutputPort_WetMssEventReceived(MssEvent mssEvent) { if (mssEvent.mssMsg.Type == MssMsgType.GeneratorModify) { this.generatorMappingMgr.RunFuncOnMappingEntry(mssEvent.mssMsg.Data1AsInt, genEntry => { switch ((GenOperation)mssEvent.mssMsg.Data2) { case GenOperation.OnOff: if (mssEvent.mssMsg.Data3 > 0) { genEntry.GenConfigInfo.Enabled = true; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = double.NaN; genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate = mssEvent.sampleTime - SAMPLES_PER_GENERATOR_UPDATE; genEntry.GenHistoryInfo.LastValueSent = double.NaN; genEntry.GenHistoryInfo.Initialized = true; } else { genEntry.GenConfigInfo.Enabled = false; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = double.NaN; genEntry.GenHistoryInfo.Initialized = false; } break; case GenOperation.PlayPause: if (mssEvent.mssMsg.Data3 > 0) { genEntry.GenConfigInfo.Enabled = true; genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate = mssEvent.sampleTime - SAMPLES_PER_GENERATOR_UPDATE; genEntry.GenHistoryInfo.LastValueSent = double.NaN; genEntry.GenHistoryInfo.Initialized = true; } else { genEntry.GenConfigInfo.Enabled = false; genEntry.GenHistoryInfo.Initialized = false; } break; case GenOperation.SetPosition: if (double.IsNaN(mssEvent.mssMsg.Data3) == false) { //TODO: The value that get's set here will not actually be used. Instead the next value will be used. genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = mssEvent.mssMsg.Data3; } break; default: Debug.Assert(false, "Unknown generator modify operation."); break; } }); } }
public void ConvertMssEventToVstMidiEvent_NoValidConversion_ReturnsNull() { MidiHandlerProtectedWrapper midiHandler = Factory_MidiHandler_Basic(); long sampleTime = 123456; MssEvent internalEvent = new MssEvent(); internalEvent.mssMsg = new MssMsg(MssMsgType.Generator, 0, 0, 0); internalEvent.sampleTime = sampleTime; VstMidiEvent convertedEvent = midiHandler.ConvertMssEventToVstMidiEventWrapper( internalEvent, sampleTime, this.hostInfoOutputPort.SampleRate); Assert.IsNull(convertedEvent); }
/// <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); }
/// <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 ReceiveWetMssEvent(MssEvent mssEvent) { Debug.Assert(mssEvent != null); lock (this.relayLock) { this.mssEventBuffer.Add(mssEvent); } if (WetMssEventsReceived != null) { WetMssEventsReceived(mssEvent); } if (this.OnlySendOnProcessingCycleEnd == false && SendingWetMssEvents != null) { SendingWetMssEvents(transferMssEventBufferContentToNewList(), 0); } }
//*******************************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 VstMidiEvent ConvertMssEventToVstMidiEventWrapper(MssEvent mssEvent, long processingCycleStartTime, double sampleRate) { return(ConvertMssEventToVstMidiEvent(mssEvent, processingCycleStartTime, sampleRate)); }
/// <summary> /// Each call to GenerateEvent() will generate the next event for genEntry. The /// next event's sample time will be set to SAMPLES_PER_GENERATOR_UPDATE more then the /// sample time for the event that was previously created for genEntry. Returns null if /// no event currently needs to be generated for this generator. /// </summary> /// <remarks> /// Preconditions: genEntry is initilaized and enabled. /// </remarks> protected MssEvent GenerateEvent(IGeneratorMappingEntry genEntry) { Debug.Assert(genEntry.GenConfigInfo.Enabled == true); Debug.Assert(genEntry.GenHistoryInfo.Initialized == true); //Stores the relative position through the period that the next event for genEntry //will occur. double relPosInPeriod; bool reachedEndOfPeriod; if (genEntry.GenConfigInfo.PeriodType == GenPeriodType.BeatSynced) { //TODO: this code does not work. relPosInPeriod can be negative which screws everything up. //It also doesn't take looping into account relPosInPeriod = GetRelPosInBeatSyncedPeriod(genEntry.GenConfigInfo, genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate + SAMPLES_PER_GENERATOR_UPDATE); reachedEndOfPeriod = false; } else if (genEntry.GenConfigInfo.PeriodType == GenPeriodType.Time || genEntry.GenConfigInfo.PeriodType == GenPeriodType.Bars) { int periodSizeInSamples = GetPeriodSizeInSamples(genEntry.GenConfigInfo); double RelativeperiodIncrement = ((double)SAMPLES_PER_GENERATOR_UPDATE) / ((double)periodSizeInSamples); //PercentThroughPeriodOnLastUpdate will be NaN the first time it's generator is updated. if (double.IsNaN(genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate) == false) { relPosInPeriod = genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate + RelativeperiodIncrement; } else { relPosInPeriod = 0; } reachedEndOfPeriod = (relPosInPeriod >= 1); //Remove the interger component of relPosInPeriod so that it is between 0 and 1. relPosInPeriod = relPosInPeriod % 1; } else { //Unexpected period type Debug.Assert(false); return(null); } Debug.Assert(relPosInPeriod >= 0); //If this generator is not set to loop and it has finished one full period then disable it //it and return null so that no more events are sent. if (genEntry.GenConfigInfo.Loop == false && reachedEndOfPeriod) { genEntry.GenConfigInfo.Enabled = false; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = 0; genEntry.GenHistoryInfo.Initialized = false; return(null); } MssMsg relPosMsg = CreateInputMsgForGenMappingEntry(genEntry, relPosInPeriod); //Processing the relPosMsg should convert it into a Generator message and apply the //equation for this generator to it's data3. List <MssMsg> processedMsgList = this.mssMsgProcessor.ProcessMssMsg(relPosMsg).ToList(); //Sample time for new event. long updatedSampleTime = genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate + SAMPLES_PER_GENERATOR_UPDATE; //Update the generator's history info. genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate = updatedSampleTime; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = relPosInPeriod; //Count could equal 0 if data 3 has been mapped above 1 or mapped to NaN. Debug.Assert(processedMsgList.Count <= 1); if (processedMsgList.Count == 0) { genEntry.GenHistoryInfo.LastValueSent = double.NaN; return(null); } //Don't bother sending the event if it is the same as the last one sent. else if (processedMsgList[0].Data3 == genEntry.GenHistoryInfo.LastValueSent) { return(null); } else { //Initialize the fields in the new event and return it. MssEvent generatedEvent = new MssEvent(); generatedEvent.mssMsg = processedMsgList[0]; generatedEvent.sampleTime = updatedSampleTime; genEntry.GenHistoryInfo.LastValueSent = generatedEvent.mssMsg.Data3; return(generatedEvent); } }
/// <summary> /// Iterates through the entries in generatorMappingManager, creates all nessary Mss /// Events, and send them to dryMssEventInputPort. This function will be called before /// each audio processing cycle ends. /// </summary> /// <param name="sampleTimeAtEndOfCycle"> /// The sample time for when the current processing cycle will end. /// </param> protected void HostInfoOutputPort_BeforeProcessingCycleEnd(long sampleTimeAtEndOfCycle) { List <int> genEntryIdList = this.generatorMappingMgr.GetEntryIdList(); foreach (int genEntryId in genEntryIdList) { this.generatorMappingMgr.RunFuncOnMappingEntry(genEntryId, (genEntry) => { //In order to generate events we need to some information about the //host. If any of this information hasn't been initialized yet then just don't //generate anything for this generator. switch (genEntry.GenConfigInfo.PeriodType) { case GenPeriodType.BeatSynced: if (this.hostInfoOutputPort.TempoIsInitialized == false || this.hostInfoOutputPort.TimeSignatureIsInitialized == false || this.hostInfoOutputPort.CalculatedBarZeroIsInitialized == false || this.hostInfoOutputPort.TransportPlayingIsInitialized == false) { return; } //If the host stopped playing then nothing will be generated for this generator //and it will need to be reinitialized when the host starts playing again. if (this.hostInfoOutputPort.TransportPlaying == false) { genEntry.GenHistoryInfo.Initialized = false; return; } break; case GenPeriodType.Time: if (this.hostInfoOutputPort.TimeSignatureIsInitialized == false) { return; } break; case GenPeriodType.Bars: if (this.hostInfoOutputPort.TempoIsInitialized == false || this.hostInfoOutputPort.TimeSignatureIsInitialized == false) { return; } break; default: Debug.Assert(false); break; } //Only enabled generators should generate anything if (genEntry.GenConfigInfo.Enabled == true) { //Initializes the history info for this generator if it has not already been //initialized. if (genEntry.GenHistoryInfo.Initialized == false) { //The GenHistoryInfo will be initialized such that it appears to have been //updated on the last processing cycle. genEntry.GenHistoryInfo.InitAllMembers( this.sampleTimeAtEndOfLastCycle, genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate, double.NaN); } //Generate events for this generator until the next event coming from this //generator would fall into the next audio processing cycle. The enabled status //of a generator can change in a call to GenerateEvent() so we need to ensure //that this generator is still enabled. while (genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate + SAMPLES_PER_GENERATOR_UPDATE <= sampleTimeAtEndOfCycle && genEntry.GenConfigInfo.Enabled == true) { MssEvent generatedEvent = GenerateEvent(genEntry); if (generatedEvent != null) { //This can be true in the following scenario. // 1. At the end of a cycle a generator generates a genmodify message // 2. The gen modify event gets caught by this class when all the wet events are sent out // which enables a generator and sets it's SampleTimeAtLastGeneratorUpdate to one cycle // before the time of the gen modify event. // 3. The newly enabled generator doesn't get generated this cycle because HostInfoOutputPort_BeforeProcessingCycleEnd // has already finished. // 4. On the next cycle the newly enabled generator starts getting generated but it has // events that should have gone out last cycle. // // Just ignoreing the events is not a great solution as they really should have been sent // out last cycle. But this does give us an easy way to prevent infinate feedback loops. if (this.sampleTimeAtEndOfLastCycle >= generatedEvent.sampleTime) { continue; } this.dryMssEventInputPort.ReceiveDryMssEvent(generatedEvent); } } } else { genEntry.GenHistoryInfo.Initialized = false; } }); } }
/// <summary> /// Event handler for MssEvents coming /// </summary> /// <param name="dryMssEvent"></param> protected void dryMssEventOutputPort_DryMssEventRecieved(MssEvent dryMssEvent) { if (this.InvokeRequired) { this.BeginInvoke(new Action<MssEvent>(dryMssEventOutputPort_DryMssEventRecieved), dryMssEvent); return; } MssMsg curMsg = dryMssEvent.mssMsg; if (this.learnMode != LearnMode.Off && curMsg.Type != MssMsgType.NoteOff && curMsg.Type != MssMsgType.Generator) { if (curMsg.Type == MssMsgType.NoteOn) { curMsg.Type = MssMsgType.Note; } ComboBox curTypeCombo = null; if (this.learnMode == LearnMode.In) { curTypeCombo = this.inTypeCombo; } else if (this.learnMode == LearnMode.Out) { curTypeCombo = this.outTypeCombo; } else { //Unknown learn mode Debug.Assert(false); return; } string newTypeName = MssMsg.MssMsgTypeNames[(int)curMsg.Type]; //Ensure that the type of the message recieved can be assigned to the current type combo box. if (curTypeCombo.FindStringExact(newTypeName) != -1) { //This will trigger the corresponding MsgMetadata to be regenerated. curTypeCombo.Text = newTypeName; } else { return; } MssMsgRangeEntryMetadata curEntryMetadata; if(this.learnMode == LearnMode.In) { curEntryMetadata = this.inMsgMetadata; } else //(this.learnMode == LearnMode.Out) { curEntryMetadata = this.outMsgMetadata; } IMssMsgRange learnedRange = new MssMsgRange(); learnedRange.MsgType = curMsg.Type; //If the type is the same as the last message and either data1 or data2 has changed //then treat this as a range of notes. if (this.lastMsgReceived != null && this.lastMsgReceived.Type == curMsg.Type && (this.lastMsgReceived.Data1 != curMsg.Data1 || this.lastMsgReceived.Data2 != curMsg.Data2)) { learnedRange.Data1RangeBottom = Math.Min(this.lastMsgReceived.Data1, curMsg.Data1); learnedRange.Data1RangeTop = Math.Max(this.lastMsgReceived.Data1, curMsg.Data1); learnedRange.Data2RangeBottom = Math.Min(this.lastMsgReceived.Data2, curMsg.Data2); learnedRange.Data2RangeTop = Math.Max(this.lastMsgReceived.Data2, curMsg.Data2); } else { learnedRange.Data1RangeBottom = curMsg.Data1; learnedRange.Data1RangeTop = curMsg.Data1; learnedRange.Data2RangeBottom = curMsg.Data2; learnedRange.Data2RangeTop = curMsg.Data2; } curEntryMetadata.UseExistingMsgRange(learnedRange); if (this.learnMode == LearnMode.In) { inMsgMetadata.ValidateEntryField1(); inMsgMetadata.ValidateEntryField2(); } else //(this.learnMode == LearnMode.Out) { outMsgMetadata.ValidateEntryField1(); outMsgMetadata.ValidateEntryField2(); } this.lastMsgReceived = curMsg; } }
public void dryMssEventInputPort_DryMssEventRecieved(MssEvent dryMssEvent) { numDryEventsReceivedByRelay++; }
/// <summary> /// Each call to GenerateEvent() will generate the next event for genEntry. The /// next event's sample time will be set to SAMPLES_PER_GENERATOR_UPDATE more then the /// sample time for the event that was previously created for genEntry. Returns null if /// no event currently needs to be generated for this generator. /// </summary> /// <remarks> /// Preconditions: genEntry is initilaized and enabled. /// </remarks> protected MssEvent GenerateEvent(IGeneratorMappingEntry genEntry) { Debug.Assert(genEntry.GenConfigInfo.Enabled == true); Debug.Assert(genEntry.GenHistoryInfo.Initialized == true); //Stores the relative position through the period that the next event for genEntry //will occur. double relPosInPeriod; bool reachedEndOfPeriod; if (genEntry.GenConfigInfo.PeriodType == GenPeriodType.BeatSynced) { //TODO: this code does not work. relPosInPeriod can be negative which screws everything up. //It also doesn't take looping into account relPosInPeriod = GetRelPosInBeatSyncedPeriod(genEntry.GenConfigInfo, genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate + SAMPLES_PER_GENERATOR_UPDATE); reachedEndOfPeriod = false; } else if (genEntry.GenConfigInfo.PeriodType == GenPeriodType.Time || genEntry.GenConfigInfo.PeriodType == GenPeriodType.Bars) { int periodSizeInSamples = GetPeriodSizeInSamples(genEntry.GenConfigInfo); double RelativeperiodIncrement = ((double)SAMPLES_PER_GENERATOR_UPDATE) / ((double)periodSizeInSamples); //PercentThroughPeriodOnLastUpdate will be NaN the first time it's generator is updated. if (double.IsNaN(genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate) == false) { relPosInPeriod = genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate + RelativeperiodIncrement; } else { relPosInPeriod = 0; } reachedEndOfPeriod = (relPosInPeriod >= 1); //Remove the interger component of relPosInPeriod so that it is between 0 and 1. relPosInPeriod = relPosInPeriod % 1; } else { //Unexpected period type Debug.Assert(false); return null; } Debug.Assert(relPosInPeriod >= 0); //If this generator is not set to loop and it has finished one full period then disable it //it and return null so that no more events are sent. if (genEntry.GenConfigInfo.Loop == false && reachedEndOfPeriod) { genEntry.GenConfigInfo.Enabled = false; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = 0; genEntry.GenHistoryInfo.Initialized = false; return null; } MssMsg relPosMsg = CreateInputMsgForGenMappingEntry(genEntry, relPosInPeriod); //Processing the relPosMsg should convert it into a Generator message and apply the //equation for this generator to it's data3. List<MssMsg> processedMsgList = this.mssMsgProcessor.ProcessMssMsg(relPosMsg).ToList(); //Sample time for new event. long updatedSampleTime = genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate + SAMPLES_PER_GENERATOR_UPDATE; //Update the generator's history info. genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate = updatedSampleTime; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = relPosInPeriod; //Count could equal 0 if data 3 has been mapped above 1 or mapped to NaN. Debug.Assert(processedMsgList.Count <= 1); if (processedMsgList.Count == 0) { genEntry.GenHistoryInfo.LastValueSent = double.NaN; return null; } //Don't bother sending the event if it is the same as the last one sent. else if (processedMsgList[0].Data3 == genEntry.GenHistoryInfo.LastValueSent) { return null; } else { //Initialize the fields in the new event and return it. MssEvent generatedEvent = new MssEvent(); generatedEvent.mssMsg = processedMsgList[0]; generatedEvent.sampleTime = updatedSampleTime; genEntry.GenHistoryInfo.LastValueSent = generatedEvent.mssMsg.Data3; return generatedEvent; } }
/// <summary> /// Listens for GeneratorToggle messages /// </summary> protected void WetMssEventOutputPort_WetMssEventReceived(MssEvent mssEvent) { if (mssEvent.mssMsg.Type == MssMsgType.GeneratorModify) { this.generatorMappingMgr.RunFuncOnMappingEntry(mssEvent.mssMsg.Data1AsInt, genEntry => { switch ((GenOperation)mssEvent.mssMsg.Data2) { case GenOperation.OnOff: if (mssEvent.mssMsg.Data3 > 0) { genEntry.GenConfigInfo.Enabled = true; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = double.NaN; genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate = mssEvent.sampleTime - SAMPLES_PER_GENERATOR_UPDATE; genEntry.GenHistoryInfo.LastValueSent = double.NaN; genEntry.GenHistoryInfo.Initialized = true; } else { genEntry.GenConfigInfo.Enabled = false; genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = double.NaN; genEntry.GenHistoryInfo.Initialized = false; } break; case GenOperation.PlayPause: if (mssEvent.mssMsg.Data3 > 0) { genEntry.GenConfigInfo.Enabled = true; genEntry.GenHistoryInfo.SampleTimeAtLastGeneratorUpdate = mssEvent.sampleTime - SAMPLES_PER_GENERATOR_UPDATE; genEntry.GenHistoryInfo.LastValueSent = double.NaN; genEntry.GenHistoryInfo.Initialized = true; } else { genEntry.GenConfigInfo.Enabled = false; genEntry.GenHistoryInfo.Initialized = false; } break; case GenOperation.SetPosition: if (double.IsNaN(mssEvent.mssMsg.Data3) == false) { //TODO: The value that get's set here will not actually be used. Instead the next value will be used. genEntry.GenHistoryInfo.PercentThroughPeriodOnLastUpdate = mssEvent.mssMsg.Data3; } break; default: Debug.Assert(false,"Unknown generator modify operation."); break; } }); } }
/// <summary> /// Event handler for MssEvents coming /// </summary> /// <param name="dryMssEvent"></param> protected void dryMssEventOutputPort_DryMssEventRecieved(MssEvent dryMssEvent) { if (this.InvokeRequired) { this.BeginInvoke(new Action <MssEvent>(dryMssEventOutputPort_DryMssEventRecieved), dryMssEvent); return; } MssMsg curMsg = dryMssEvent.mssMsg; if (this.learnMode != LearnMode.Off && curMsg.Type != MssMsgType.NoteOff && curMsg.Type != MssMsgType.Generator) { if (curMsg.Type == MssMsgType.NoteOn) { curMsg.Type = MssMsgType.Note; } ComboBox curTypeCombo = null; if (this.learnMode == LearnMode.In) { curTypeCombo = this.inTypeCombo; } else if (this.learnMode == LearnMode.Out) { curTypeCombo = this.outTypeCombo; } else { //Unknown learn mode Debug.Assert(false); return; } string newTypeName = MssMsg.MssMsgTypeNames[(int)curMsg.Type]; //Ensure that the type of the message recieved can be assigned to the current type combo box. if (curTypeCombo.FindStringExact(newTypeName) != -1) { //This will trigger the corresponding MsgMetadata to be regenerated. curTypeCombo.Text = newTypeName; } else { return; } MssMsgRangeEntryMetadata curEntryMetadata; if (this.learnMode == LearnMode.In) { curEntryMetadata = this.inMsgMetadata; } else //(this.learnMode == LearnMode.Out) { curEntryMetadata = this.outMsgMetadata; } IMssMsgRange learnedRange = new MssMsgRange(); learnedRange.MsgType = curMsg.Type; //If the type is the same as the last message and either data1 or data2 has changed //then treat this as a range of notes. if (this.lastMsgReceived != null && this.lastMsgReceived.Type == curMsg.Type && (this.lastMsgReceived.Data1 != curMsg.Data1 || this.lastMsgReceived.Data2 != curMsg.Data2)) { learnedRange.Data1RangeBottom = Math.Min(this.lastMsgReceived.Data1, curMsg.Data1); learnedRange.Data1RangeTop = Math.Max(this.lastMsgReceived.Data1, curMsg.Data1); learnedRange.Data2RangeBottom = Math.Min(this.lastMsgReceived.Data2, curMsg.Data2); learnedRange.Data2RangeTop = Math.Max(this.lastMsgReceived.Data2, curMsg.Data2); } else { learnedRange.Data1RangeBottom = curMsg.Data1; learnedRange.Data1RangeTop = curMsg.Data1; learnedRange.Data2RangeBottom = curMsg.Data2; learnedRange.Data2RangeTop = curMsg.Data2; } curEntryMetadata.UseExistingMsgRange(learnedRange); if (this.learnMode == LearnMode.In) { inMsgMetadata.ValidateEntryField1(); inMsgMetadata.ValidateEntryField2(); } else //(this.learnMode == LearnMode.Out) { outMsgMetadata.ValidateEntryField1(); outMsgMetadata.ValidateEntryField2(); } this.lastMsgReceived = curMsg; } }