Skip to content

Commit 82850c1

Browse files
more midinette stuff
1 parent db129fe commit 82850c1

File tree

4 files changed

+276
-15
lines changed

4 files changed

+276
-15
lines changed

src/Midinette.Elektron/Elektron.MachineDrum.fs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ with
214214
| i -> failwithf "unknown parameter for cc %i" i
215215
type MDMachineSettings(bytes: byte array, offset: int, machineType: MDMachineType) =
216216
let baseAddress = 0x1a + (offset * 24)
217+
let getAt a = bytes.[baseAddress + a]
218+
let setAt a v = bytes.[baseAddress + a] <- (v &&& 0b01111111uy)
217219
member x.SynthesisParameters = getSlice baseAddress 8 bytes
218220
member x.Parameter1 = bytes.[baseAddress + 0]
219221
member x.Parameter2 = bytes.[baseAddress + 1]
@@ -234,8 +236,8 @@ type MDMachineSettings(bytes: byte array, offset: int, machineType: MDMachineTyp
234236
member x.Distortion = bytes.[baseAddress + 16]
235237
member x.Volume = bytes.[baseAddress + 17]
236238
member x.Pan = bytes.[baseAddress + 18]
237-
member x.DelaySend = bytes.[baseAddress + 19]
238-
member x.ReverbSend = bytes.[baseAddress + 20]
239+
member x.DelaySend with get () = getAt 19 and set v = setAt 19 v
240+
member x.ReverbSend with get () = getAt 20 and set v = setAt 20 v
239241
member x.LFOSpeed = bytes.[baseAddress + 21]
240242
member x.LFODepth = bytes.[baseAddress + 22]
241243
member x.LFOShapeMix = bytes.[baseAddress + 23]
@@ -682,8 +684,8 @@ with
682684
| v -> failwithf "unknown status type %i" v
683685

684686
type TriggerType =
685-
| TriggerChannel of Track
686-
| TriggerPattern of PatternLocator
687+
| TriggerChannel of mdTrack: Track
688+
| TriggerPattern of pattern: PatternLocator
687689
| UnknownTrigger of value: byte
688690

689691
type NoteTriggerType = NoteTriggerType of note: byte * TriggerType
@@ -744,8 +746,8 @@ type KeyMapStructure(bytes: byte array) =
744746
)
745747
|> Array.sortBy snd
746748

747-
member __.GetTriggerNoteForChannel channel =
748-
match notePerTriggerLookup.TryGetValue (TriggerChannel channel) with
749+
member __.GetTriggerNoteForChannel mdTrack =
750+
match notePerTriggerLookup.TryGetValue (TriggerChannel mdTrack) with
749751
| true, note -> Some note
750752
| _ -> None
751753

@@ -936,7 +938,7 @@ type MachineDrumEvent =
936938
| TrackParameter of Track * MDTrackParameter * value: byte
937939
| TrackTrigger of Track * velocity: byte
938940
| TrackRelease of Track
939-
| PatternChanged of byte
941+
| PatternChanged of PatternLocator
940942
| LFOSetting of Track * LFOEvent
941943
| DelaySetting of DelayParameter * value: byte
942944
| ReverbSetting of ReverbParameter * value: byte
@@ -1017,7 +1019,11 @@ type MachineDrum(inPort: IMidiInput<int>, outPort: IMidiOutput<int>, getSysexNow
10171019
Some (MidiOutputData.Message (MidiMessage.NoteOn channel note velocity))
10181020
else
10191021
Some (MidiOutputData.Message (MidiMessage.NoteOff channel note velocity))
1020-
1022+
let makeCC track parameter value =
1023+
let cc = MDTrackParameter.GetCCForTrack parameter track
1024+
let channel = Track.midiBaseChannelOffset track + channel
1025+
MidiMessage.CC channel cc value
1026+
|> MidiOutputData.Message
10211027
let makeProgramChange program =
10221028
MidiMessage.ProgramChange channel program
10231029
|> MidiOutputData.Message
@@ -1028,7 +1034,7 @@ type MachineDrum(inPort: IMidiInput<int>, outPort: IMidiOutput<int>, getSysexNow
10281034
| TrackTrigger(track, velocity) -> makeNote note velocity true |> Option.get |> some
10291035
| TrackRelease(track) -> makeNote note 0uy false |> Option.get |> some
10301036
| TrackLevel(track, level) -> none
1031-
| TrackParameter(track, parameter, value) -> none
1037+
| TrackParameter(track, parameter, value) -> makeCC track parameter value |> some
10321038
| PatternChanged pattern -> none
10331039
| Unknown message -> message |> MidiOutputData.Message |> some
10341040
| Sysex data -> data |> MidiOutputData.Sysex |> some
@@ -1038,7 +1044,7 @@ type MachineDrum(inPort: IMidiInput<int>, outPort: IMidiOutput<int>, getSysexNow
10381044

10391045

10401046

1041-
member x.SendEvents mdGlobals mdEvents getNow =
1047+
member x.SendEvents getNow mdGlobals mdEvents =
10421048
match mdGlobals with
10431049
| Some globals ->
10441050
let now = getNow ()
@@ -1128,7 +1134,7 @@ type MachineDrumEventListener(md: MachineDrum, getNow : unit -> int) =
11281134
| Some mdGlobalSettings ->
11291135
let midiBaseChannel = mdGlobalSettings.MidiBaseChannel
11301136
if message.MessageType = MidiMessageType.ProgramChange && message.Channel = Some midiBaseChannel then
1131-
PatternChanged message.Data1
1137+
PatternChanged (PatternLocator.FromByte message.Data1)
11321138
elif MachineDrumEventParser.isMachineDrumControlChange midiBaseChannel message then
11331139
let channel = message.Channel.Value
11341140
let cc = message.Data1

src/Midinette.Elektron/Elektron.MonoMachine.fs

Lines changed: 235 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,238 @@ type MonoMachineParameter =
454454
| EffectDelayFeedback
455455
| EffectDelayFilterBase
456456
| EffectDelayFilterWidth
457-
| LFOPage
458-
| LFODest
459-
| LFOTrig
457+
| LFOPage of OneToThree
458+
| LFODest of OneToThree
459+
| LFOTrig of OneToThree
460+
| LFOWave of OneToThree
461+
| LFOMultiplier of OneToThree
462+
| LFOSpeed of OneToThree
463+
| LFOInterlace of OneToThree
464+
| LFODepth of OneToThree
465+
466+
467+
module MonoMachineControlChangeLogic =
468+
469+
let getLFOCCPageBase lfoPage =
470+
match lfoPage with
471+
| OneToThree.One -> 88uy
472+
| OneToThree.Two -> 104uy
473+
| OneToThree.Three-> 112uy
474+
475+
let isCCLFOPageForPage page cc =
476+
let baseCC = getLFOCCPageBase page
477+
cc >= baseCC && cc < baseCC + 8uy
478+
479+
let getLfoParameter cc =
480+
let page = OneToThree.One
481+
let pageBase = getLFOCCPageBase page
482+
if isCCLFOPageForPage page cc then
483+
match cc - pageBase with
484+
| 0uy -> LFOPage page |> Some
485+
| 1uy -> LFODest page |> Some
486+
| 2uy -> LFOTrig page |> Some
487+
| 3uy -> LFOWave page |> Some
488+
| 4uy -> LFOMultiplier page |> Some
489+
| 5uy -> LFOSpeed page |> Some
490+
| 6uy -> LFOInterlace page |> Some
491+
| 7uy -> LFODepth page |> Some
492+
| _ -> None
493+
else
494+
None
495+
496+
497+
498+
let getCC parameter =
499+
match parameter with
500+
| SynthParam1 -> 48uy | SynthParam2 -> 49uy | SynthParam3 -> 50uy | SynthParam4 -> 51uy
501+
| SynthParam5 -> 52uy | SynthParam6 -> 53uy | SynthParam7 -> 54uy | SynthParam8 -> 55uy
502+
| AmplAttack -> 56uy | AmplHold -> 57uy | AmplDecay -> 58uy | AmplRelease -> 59uy
503+
| AmplDistortion -> 60uy | AmplVolume -> 61uy | AmplPan -> 62uy | AmplPortamento -> 63uy
504+
| FilterBase -> 72uy | FilterWidth -> 73uy | FilterHighPassQ -> 74uy | FilterLowPassQ -> 75uy
505+
| FilterAttack -> 76uy | FilterDecay -> 77uy | FilterBaseOffset -> 78uy | FilterWidthOffset -> 79uy
506+
| EffectEqFrequency -> 80uy | EffectEqGain -> 81uy | EffectSampleRateReduction -> 82uy | EffectDelayTime -> 83uy
507+
| EffectDelaySend -> 84uy | EffectDelayFeedback -> 85uy | EffectDelayFilterBase -> 86uy | EffectDelayFilterWidth -> 87uy
508+
| LFOPage page -> getLFOCCPageBase page + 0uy
509+
| LFODest page -> getLFOCCPageBase page + 1uy
510+
| LFOTrig page -> getLFOCCPageBase page + 2uy
511+
| LFOWave page -> getLFOCCPageBase page + 3uy
512+
| LFOMultiplier page -> getLFOCCPageBase page + 4uy
513+
| LFOSpeed page -> getLFOCCPageBase page + 5uy
514+
| LFOInterlace page -> getLFOCCPageBase page + 6uy
515+
| LFODepth page -> getLFOCCPageBase page + 7uy
516+
517+
let getFromCC cc =
518+
match cc with
519+
| 48uy -> Some SynthParam1
520+
| 49uy -> Some SynthParam2
521+
| 50uy -> Some SynthParam3
522+
| 51uy -> Some SynthParam4
523+
| 52uy -> Some SynthParam5
524+
| 53uy -> Some SynthParam6
525+
| 54uy -> Some SynthParam7
526+
| 55uy -> Some SynthParam8
527+
| 56uy -> Some AmplAttack
528+
| 57uy -> Some AmplHold
529+
| 58uy -> Some AmplDecay
530+
| 59uy -> Some AmplRelease
531+
| 60uy -> Some AmplDistortion
532+
| 61uy -> Some AmplVolume
533+
| 62uy -> Some AmplPan
534+
| 63uy -> Some AmplPortamento
535+
| 72uy -> Some FilterBase
536+
| 73uy -> Some FilterWidth
537+
| 74uy -> Some FilterHighPassQ
538+
| 75uy -> Some FilterLowPassQ
539+
| 76uy -> Some FilterAttack
540+
| 77uy -> Some FilterDecay
541+
| 78uy -> Some FilterBaseOffset
542+
| 79uy -> Some FilterWidthOffset
543+
| 80uy -> Some EffectEqFrequency
544+
| 81uy -> Some EffectEqGain
545+
| 82uy -> Some EffectSampleRateReduction
546+
| 83uy -> Some EffectDelayTime
547+
| 84uy -> Some EffectDelaySend
548+
| 85uy -> Some EffectDelayFeedback
549+
| 86uy -> Some EffectDelayFilterBase
550+
| 87uy -> Some EffectDelayFilterWidth
551+
| cc ->
552+
getLfoParameter cc
553+
554+
type LFOEvent =
555+
| AssignDest of Track * MonoMachineParameter
556+
557+
558+
type MonoMachineEvent =
559+
| TrackLevel of Track * value: byte
560+
| TrackParameter of Track * MonoMachineParameter * value: byte
561+
| TrackTrigger of Track * note: byte * velocity: byte
562+
| TrackRelease of Track * note: byte * velocity: byte
563+
| PatternChanged of PatternLocator
564+
| LFOSetting of Track * LFOEvent
565+
| Unknown of MidiMessage
566+
| MonoMachineSysex of MonoMachineSysexResponse
567+
| Sysex of byte array
568+
| KitChanged of byte
569+
| SequencerStarted
570+
| SequencerStopped
571+
| PatternSelected of PatternLocator
572+
//| Note of Track * noteNumber: byte * velocity: byte
573+
574+
575+
576+
577+
type TimestampedMessage<'t> = {
578+
Timestamp : int
579+
Message: 't
580+
}
581+
582+
583+
type MonoMachineEventListener(getNow: unit -> int, mm: MonoMachine) =
584+
let settings = mm.CurrentGlobalSettings |> Option.map GlobalSettings.FromSysex
585+
//let settings = { GlobalSettings.midiBaseChannel = 0uy }
586+
let midiIn = mm.MidiOutPort
587+
let midiRealtimeState = Midi.Registers.MidiRealtimeState()
588+
let event = new Event<_>()
589+
590+
let makeMessage timestamp m = { Timestamp = timestamp; Message = m}
591+
592+
let onChannelMessage (midiEvent: MidiEvent<_>) =
593+
match settings with
594+
| None -> Unknown midiEvent.Message
595+
| Some settings ->
596+
let message = midiEvent.Message
597+
let messageChannel = message.Channel.Value
598+
let midiChannelIsTrack = messageChannel >= settings.midiChannel && messageChannel < (settings.midiChannel + 6uy)
599+
if midiChannelIsTrack then
600+
let track = Track.FromByte (byte (messageChannel - settings.midiChannel))
601+
match message with
602+
| Midi.MessageMatching.NoteOn (_, note, velocity) -> TrackTrigger(track, note, velocity)
603+
| Midi.MessageMatching.NoteOff (_, note, velocity) -> TrackRelease(track, note, velocity)
604+
| Midi.MessageMatching.ProgramChange {program = program} ->
605+
606+
let locator = PatternLocator.FromByte program
607+
PatternSelected(locator)
608+
| _ -> Unknown message
609+
610+
611+
else
612+
Unknown message
613+
614+
let onSysexMessage sysex =
615+
Sysex sysex
616+
617+
let realtimeListener = midiIn.RealtimeMessageReceived.Subscribe(fun m ->
618+
let oldStarted = midiRealtimeState.started
619+
midiRealtimeState.UpdateWithEvent m.Message
620+
if oldStarted <> midiRealtimeState.started then
621+
{ Timestamp = m.Timestamp; Message = (if midiRealtimeState.started then SequencerStarted else SequencerStopped)} |> event.Trigger
622+
)
623+
let channelMessageListener = midiIn.ChannelMessageReceived.Subscribe(fun m ->
624+
//midiBaseChannel
625+
let message = onChannelMessage m
626+
{ Timestamp = m.Timestamp; Message = message } |> event.Trigger
627+
)
628+
let sysexListener = midiIn.SysexReceived.Subscribe(fun m ->
629+
let timestamp = getNow()
630+
let message = onSysexMessage m
631+
{ Timestamp = timestamp; Message = message } |> event.Trigger
632+
)
633+
interface System.IDisposable with
634+
member x.Dispose() =
635+
realtimeListener.Dispose()
636+
sysexListener.Dispose()
637+
channelMessageListener.Dispose()
638+
639+
[<CLIEvent>] member x.Event = event.Publish
640+
641+
642+
(*
643+
type MonoMachineEventListener(mnm: MonoMachine, getNow : unit -> int) =
644+
let mutable mnmGlobals = mnm.CurrentGlobalSettings
645+
let midiIn = mnm.MidiOutPort
646+
let event = new Event<_>()
647+
648+
let onChannelMessage (midiEvent: MidiEvent<_>) =
649+
let message = midiEvent.Message
650+
let messageChannel = midiEvent.Message.Channel.Value
651+
match mnmGlobals with
652+
| None ->
653+
Unknown message
654+
| Some globals ->
655+
656+
let midiBaseChannel = globals.MidiBaseChannel
657+
let track =
658+
if messageChannel >= midiBaseChannel && messageChannel < midiBaseChannel + 6 then
659+
Some (Track.FromByte (channel - midiBaseChannel))
660+
else
661+
None
662+
663+
match message with
664+
| ProgramChange {_;program;other} -> PatternChanged (PatternLocator.FromByte program)
665+
| CC {_;control;value} ->
666+
match track with
667+
| Some track ->
668+
match MonoMachineControlChangeLogic.getFromCC control with
669+
| Some mnmParam -> TrackParameter(track,mnmParam,value)
670+
| None -> Unknown message
671+
| None -> Unknown message
672+
| None -> Unknown message
673+
674+
let channelMessageListener = midiIn.ChannelMessageReceived.Subscribe(fun m ->
675+
let message = onChannelMessage m
676+
{ Timestamp = (m.Timestamp); Message = message } |> event.Trigger
677+
)
678+
let onSysexMessage (sysex: byte array) =
679+
Sysex sysex
680+
681+
let sysexListener = midiIn.SysexReceived.Subscribe(fun m ->
682+
// TODO TODO
683+
let timestamp = getNow()
684+
let message = onSysexMessage m
685+
{ Timestamp = timestamp; Message = message } |> event.Trigger
686+
)
687+
interface IDisposable with
688+
member x.Dispose() =
689+
sysexListener.Dispose()
690+
channelMessageListener.Dispose()
691+
*)

src/Midinette/Midi.MessageMatching.fs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,24 @@ module MessageMatching =
77
program: byte
88
other: byte
99
}
10+
type ControlChange = {
11+
channel: byte
12+
control: byte
13+
value: byte
14+
15+
}
1016
let (|NoteOn|_|) (midiMessage: MidiMessage) =
1117
if midiMessage.MessageType = MidiMessageType.NoteOn then
1218
Some (midiMessage.Channel.Value, (*note*)midiMessage.Data1, (*velocity*)midiMessage.Data2)
1319
else
1420
None
1521

22+
let (|NoteOff|_|) (midiMessage: MidiMessage) =
23+
if midiMessage.MessageType = MidiMessageType.NoteOff then
24+
Some (midiMessage.Channel.Value, (*note*)midiMessage.Data1, (*velocity*)midiMessage.Data2)
25+
else
26+
None
27+
1628
let (|ProgramChange|_|) (midiMessage: MidiMessage) =
1729
if midiMessage.MessageType = MidiMessageType.ProgramChange then
1830
Some {channel = midiMessage.Channel.Value; program = midiMessage.Data1; other = midiMessage.Data2 }
@@ -25,7 +37,7 @@ module MessageMatching =
2537
&& (Option.isNone channel || midiMessage.Channel = channel)
2638
&& midiMessage.Data1 = ccNumber
2739
then
28-
Some(midiMessage.Data2)
40+
Some { channel = midiMessage.Channel.Value; control = midiMessage.Data1; value = midiMessage.Data2}
2941
else
3042
None
3143

src/Midinette/Midi.Registers.fs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@ module Midi.Registers
22

33
open Midi
44
open System.Collections.Generic
5+
type MidiRealtimeState =
6+
val mutable started : bool
7+
new () = {started = false}
8+
member this.UpdateWithEvent (midiMessage: MidiMessage) =
9+
match midiMessage.MessageType with
10+
| MidiMessageType.Start ->
11+
this.started <- true
12+
| MidiMessageType.Stop ->
13+
this.started <- false
14+
| _ -> ()
15+
// member this.started = started
516

617
type MidiChannelState<'timestamp> =
718
val seenControllers : HashSet<byte>

0 commit comments

Comments
 (0)