tidal-midi 0.8.2 → 0.9
raw patch · 21 files changed
+2599/−577 lines, 21 filesdep ~tidalnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: tidal
API changes (from Hackage documentation)
- Sound.Tidal.MIDI.Control: [vdefault] :: ControlChange -> Double
- Sound.Tidal.MIDI.Stream: send :: Integral t1 => Output -> t1 -> ControllerShape -> t -> Tempo -> Int -> Double -> MidiMap -> [(a, Value)] -> IO ()
- Sound.Tidal.MIDI.SynthParams: accelerate :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: bandf :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: bandq :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: begin :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: channel :: Pattern Int -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: coarse :: Pattern Int -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: crush :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: cut :: Pattern Int -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: cutoff :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: cutoffegint :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: delay :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: delayfeedback :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: delaytime :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: detune :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: dry :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: end :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: gain :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: grp :: [Param] -> Pattern String -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: hcutoff :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: hresonance :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: loop :: Pattern Int -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: n :: Pattern Int -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: nudge :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: offset :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: orbit :: Pattern Int -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: pan :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: resonance :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: room :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: s :: Pattern String -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: shape :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: size :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: sound :: Pattern String -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: speed :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: unit :: Pattern String -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: velocity :: Pattern Double -> ParamPattern
- Sound.Tidal.MIDI.SynthParams: vowel :: Pattern String -> ParamPattern
- Sound.Tidal.MIDI.System1M: oscKeys :: Shape
- Sound.Tidal.MIDI.VolcaBass: bass :: Shape
- Sound.Tidal.MIDI.VolcaBass: bassController :: ControllerShape
- Sound.Tidal.MIDI.VolcaBeats: beats :: Shape
- Sound.Tidal.MIDI.VolcaBeats: beatsController :: ControllerShape
- Sound.Tidal.MIDI.VolcaKeys: keys :: Shape
- Sound.Tidal.MIDI.VolcaKeys: keysController :: ControllerShape
+ Sound.Tidal.MIDI.Ambika: acrush :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: allnotesoff :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: allsoundsoff :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: ambikaController :: ControllerShape
+ Sound.Tidal.MIDI.Ambika: ambikaSynth :: Shape
+ Sound.Tidal.MIDI.Ambika: arpdir :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: arpmode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: arpoct :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: arppat :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: arpres :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env1a :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env1d :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env1r :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env1s :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env2a :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env2d :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env2r :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env2s :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env3a :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env3d :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env3r :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: env3s :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: f1cutoff :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: f1res :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: f2cutoff :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: f2mode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: f2res :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: filtermode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: fuzz :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: growl :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo1rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo1shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo1sync :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo2rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo2shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo2sync :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo3rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo3shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo3sync :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo4rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo4shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: lfo4sync :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: noiselevel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc1detune :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc1param :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc1range :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc1shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc2detune :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc2param :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc2range :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: osc2shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: parttuning :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: polymode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: resetallcontrollers :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: sublevel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: subshape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: tuningspread :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: xmodamount :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Ambika: xmodtype :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: bloController :: ControllerShape
+ Sound.Tidal.MIDI.Blofeld: blofeld :: Shape
+ Sound.Tidal.MIDI.Blofeld: lforate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: noise :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: noisecol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: noisepan :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: octave_p :: Param
+ Sound.Tidal.MIDI.Blofeld: osc1fm :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: osc1pan :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: osc1pw :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: osc1pwm :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: osc1shape :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: osc1vol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: ringmod :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: ringpan :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Blofeld: semitone_p :: Param
+ Sound.Tidal.MIDI.CC: cc0 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc1 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc10 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc100 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc101 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc102 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc103 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc104 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc105 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc106 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc107 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc108 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc109 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc11 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc110 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc111 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc112 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc113 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc114 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc115 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc116 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc117 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc118 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc119 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc12 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc120 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc121 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc122 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc123 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc124 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc125 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc126 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc127 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc13 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc14 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc15 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc16 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc17 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc18 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc19 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc2 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc20 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc21 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc22 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc23 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc24 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc25 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc26 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc27 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc28 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc29 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc3 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc30 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc31 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc32 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc33 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc34 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc35 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc36 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc37 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc38 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc39 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc4 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc40 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc41 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc42 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc43 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc44 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc45 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc46 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc47 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc48 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc49 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc5 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc50 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc51 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc52 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc53 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc54 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc55 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc56 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc57 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc58 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc59 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc6 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc60 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc61 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc62 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc63 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc64 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc65 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc66 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc67 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc68 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc69 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc7 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc70 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc71 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc72 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc73 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc74 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc75 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc76 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc77 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc78 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc79 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc8 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc80 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc81 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc82 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc83 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc84 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc85 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc86 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc87 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc88 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc89 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc9 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc90 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc91 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc92 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc93 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc94 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc95 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc96 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc97 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc98 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: cc99 :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.CC: ccall :: Shape
+ Sound.Tidal.MIDI.CC: ccallController :: ControllerShape
+ Sound.Tidal.MIDI.Control: computeTiming :: Tempo -> Ratio Integer -> MIDINoteShape -> ((Int, Int, Ratio Integer), Double)
+ Sound.Tidal.MIDI.Control: midiShape :: Shape
+ Sound.Tidal.MIDI.Control: n_p :: Param
+ Sound.Tidal.MIDI.Control: type MIDINoteShape = ParamMap
+ Sound.Tidal.MIDI.GMPerc: balance :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.GMPerc: chorus :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.GMPerc: gmperc :: Shape
+ Sound.Tidal.MIDI.GMPerc: gmpercController :: ControllerShape
+ Sound.Tidal.MIDI.GMPerc: perc :: Pattern String -> ParamPattern
+ Sound.Tidal.MIDI.GMPerc: percN :: String -> Int
+ Sound.Tidal.MIDI.GMPerc: reverb :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MBase01: eqlzr :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MBase01: harmonics :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MBase01: mbase01 :: Shape
+ Sound.Tidal.MIDI.MBase01: mbase01Controller :: ControllerShape
+ Sound.Tidal.MIDI.MBase01: noise :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MBase01: pitch :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MBase01: pulse :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MBase01: tune :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: alo :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: fae :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: fen :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: ffe :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: ffl :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: fln :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: flo :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: fwv :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: lfs :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: lss :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: matm :: Shape
+ Sound.Tidal.MIDI.MiniAtmegatron: matmController :: ControllerShape
+ Sound.Tidal.MIDI.MiniAtmegatron: pen :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: plo :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: por :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.MiniAtmegatron: pwm :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Output: Output :: ControllerShape -> PMStream -> MVar ([ParamMap], [MIDIEvent]) -> MVar OutputState -> CULong -> UTCTime -> Output
+ Sound.Tidal.MIDI.Output: [buffer] :: Output -> MVar ([ParamMap], [MIDIEvent])
+ Sound.Tidal.MIDI.Output: [bufferstate] :: Output -> MVar OutputState
+ Sound.Tidal.MIDI.Output: [conn] :: Output -> PMStream
+ Sound.Tidal.MIDI.Output: [cshape] :: Output -> ControllerShape
+ Sound.Tidal.MIDI.Output: [midistart] :: Output -> CULong
+ Sound.Tidal.MIDI.Output: [rstart] :: Output -> UTCTime
+ Sound.Tidal.MIDI.Output: changeState :: (OutputState -> OutputState) -> Output -> IO ()
+ Sound.Tidal.MIDI.Output: cutShape :: Shape -> ParamMap -> Maybe ParamMap
+ Sound.Tidal.MIDI.Output: data Output
+ Sound.Tidal.MIDI.Output: displayOutputDevices :: IO String
+ Sound.Tidal.MIDI.Output: flushBackend :: Output -> Shape -> Tempo -> Int -> IO ()
+ Sound.Tidal.MIDI.Output: makeConnection :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (ToMessageFunc, Output)
+ Sound.Tidal.MIDI.Output: makeCtrl :: MIDIChannel -> ControlChange -> MIDIDatum -> MIDITime -> [MIDIEvent]
+ Sound.Tidal.MIDI.Output: makeRawEvent :: MIDIMessage -> CULong -> PMEvent
+ Sound.Tidal.MIDI.Output: mkStore :: Int -> Output -> IO ToMessageFunc
+ Sound.Tidal.MIDI.Output: noteOff :: MIDIChannel -> MIDINote -> MIDITime -> [MIDIEvent]
+ Sound.Tidal.MIDI.Output: noteOn :: MIDIChannel -> MIDINote -> MIDIVelocity -> MIDITime -> [MIDIEvent]
+ Sound.Tidal.MIDI.Output: outputDevice :: DeviceID -> Int -> ControllerShape -> IO (Either Output PMError)
+ Sound.Tidal.MIDI.Output: readState :: (OutputState -> b) -> Output -> IO b
+ Sound.Tidal.MIDI.Output: scheduleTime :: (CULong, UTCTime) -> Double -> CULong
+ Sound.Tidal.MIDI.Output: sendevents :: Output -> Shape -> Tempo -> Tick -> [MIDIEvent] -> [MIDIEvent] -> IO ([SentEvent], [MIDIEvent])
+ Sound.Tidal.MIDI.Output: store :: Output -> Int -> Tempo -> Tick -> Onset -> Offset -> MidiMap -> ParamMap -> IO ()
+ Sound.Tidal.MIDI.Output: storeParams :: Output -> Int -> ParamMap -> IO () -> IO ()
+ Sound.Tidal.MIDI.Output: stripDefaults :: Maybe ParamMap -> Maybe ParamMap
+ Sound.Tidal.MIDI.Output: toMidiValue :: ControllerShape -> Param -> Value -> Maybe Int
+ Sound.Tidal.MIDI.Output: type MidiDeviceMap = Map String Output
+ Sound.Tidal.MIDI.Output: type OutputState = (TickedConnectionCount, ConnectionCount, [ParamMap], OutputOnline)
+ Sound.Tidal.MIDI.Output: type TimedNote = (CLong, MIDIVelocity, MIDIDuration)
+ Sound.Tidal.MIDI.Output: useOutput :: MVar MidiDeviceMap -> String -> ControllerShape -> IO (Maybe Output)
+ Sound.Tidal.MIDI.Stream: displayOutputDevices :: IO String
+ Sound.Tidal.MIDI.Synthino: arplength :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: arptranspose :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: bpm :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: filterlfodepth :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: filterlforate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: lfowaveform :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: off :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: peak :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: pitchlfodepth :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: pitchlforate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: synthino :: Shape
+ Sound.Tidal.MIDI.Synthino: synthinoController :: ControllerShape
+ Sound.Tidal.MIDI.Synthino: vol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Synthino: waveform :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.System1M: system1m :: Shape
+ Sound.Tidal.MIDI.Tetra: adsr :: Pattern String -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: aftt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: afttdst :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: arp :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: arpmode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: atk3 :: Pattern String -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: attack_p :: Param
+ Sound.Tidal.MIDI.Tetra: audiomod :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: bendrng :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: breath :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: breathdst :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: btnfreq :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: btnmode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: btnvel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: ccreset :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: chip :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: clockdiv :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: cutoff_p :: Param
+ Sound.Tidal.MIDI.Tetra: damod :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: damp :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: damt :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: datk :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dcut :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dcy3 :: Pattern String -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: ddcy :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: deamt :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: deatk :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: decay_p :: Param
+ Sound.Tidal.MIDI.Tetra: dedcy :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: derel :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dfamt :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dfatk :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dfb :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dfdcy :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dfrel :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo1a :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo1f :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo2a :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo2f :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo3a :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo3f :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo4a :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfo4f :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfoa :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dlfof :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dmix :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dmod1 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dmod2 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dmod3 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dmod4 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dnoise :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dosc :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dosc1 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dosc2 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: doublePattern :: Double -> Pattern Double
+ Sound.Tidal.MIDI.Tetra: dpw :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dpw1 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dpw2 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: drel :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dres :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dshape :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dslew :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dspread :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dsub1 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dsub2 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dvamt :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dvatk :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dvca :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dvdcy :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: dvrel :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: eamt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: eatk :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: edcy :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: edel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: emod :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: erel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: erepeat :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: esus :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: evel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: famt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fatk :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fbvol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fdcy :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fdel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: foot :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: footdst :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fourpole :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: fpoles :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: frel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fsus :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: fvel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: glidemode :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: kamt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: kbpm :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: kick :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: kmode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: knormal :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: ksplit :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: ksplitpoint :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: kstack :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo1 :: Pattern Int -> Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo1amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo1dest :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo1rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo1shape :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo1sync :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo2 :: Pattern Int -> Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo2amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo2dest :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo2rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo2shape :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo2sync :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo3 :: Pattern Int -> Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo3amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo3dest :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo3rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo3shape :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo3sync :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo4 :: Pattern Int -> Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo4amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo4dest :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo4rate :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo4shape :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfo4sync :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: lfopulse :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: lforand :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: lforsaw :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: lfosaw :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: lfotri :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: lrate :: (Num b, Ord b, Functor f) => f b -> f b
+ Sound.Tidal.MIDI.Tetra: lstep :: (Num b, Ord b, Functor f) => f b -> f b
+ Sound.Tidal.MIDI.Tetra: mcr1 :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mcr2 :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mcr3 :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mcr4 :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod1 :: Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod1amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod1dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod1src :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod2 :: Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod2amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod2dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod2src :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod3 :: Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod3amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod3dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod3src :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod4 :: Pattern Double -> Pattern Double -> Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod4amt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod4dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mod4src :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mvel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mveldst :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mwhl :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: mwhldst :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: noise :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: notesoff :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc1detune :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc1freq :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc1glide :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc1kbd :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc1shape :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc2detune :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc2freq :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc2glide :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc2kbd :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: osc2shape :: Pattern Int -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: oscmix :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: oscslop :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: oscsync :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: rel3' :: Pattern String -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: release_p :: Param
+ Sound.Tidal.MIDI.Tetra: saftert :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sbreath :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: seenv :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: seq1dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: seq2dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: seq3dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: seq4dst :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: sexpr :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sfenv :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sfoot :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: slfo1 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: slfo2 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: slfo3 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: slfo4 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: smodwh :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: snare :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: snoise :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: snote :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: spitchb :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sqn :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: sqntrig :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: sseq1 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sseq2 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sseq3 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sseq4 :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: sub1vol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: sub2vol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: sus3 :: Pattern String -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: sustain_p :: Param
+ Sound.Tidal.MIDI.Tetra: svel :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: svenv :: Pattern Double
+ Sound.Tidal.MIDI.Tetra: tetra :: Shape
+ Sound.Tidal.MIDI.Tetra: tetraController :: ControllerShape
+ Sound.Tidal.MIDI.Tetra: twopole :: ParamPattern
+ Sound.Tidal.MIDI.Tetra: unison :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: unisonkey :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: unisonmode :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: vamt :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: vcavol :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: vdel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.Tetra: vvel :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaBass: volcabass :: Shape
+ Sound.Tidal.MIDI.VolcaBass: volcabassController :: ControllerShape
+ Sound.Tidal.MIDI.VolcaBeats: volcabeats :: Shape
+ Sound.Tidal.MIDI.VolcaBeats: volcabeatsController :: ControllerShape
+ Sound.Tidal.MIDI.VolcaFM: algtm :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: arp :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: arpdiv :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: carattack :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: cardecay :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: modattack :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: moddecay :: Pattern Double -> ParamPattern
+ Sound.Tidal.MIDI.VolcaFM: volcafm :: Shape
+ Sound.Tidal.MIDI.VolcaFM: volcafmController :: ControllerShape
+ Sound.Tidal.MIDI.VolcaKeys: volcakeys :: Shape
+ Sound.Tidal.MIDI.VolcaKeys: volcakeysController :: ControllerShape
- Sound.Tidal.MIDI.Control: CC :: Param -> Int -> (Int, Int) -> Double -> RangeMapFunc -> ControlChange
+ Sound.Tidal.MIDI.Control: CC :: Param -> Int -> (Int, Int) -> RangeMapFunc -> ControlChange
- Sound.Tidal.MIDI.Control: NRPN :: Param -> Int -> (Int, Int) -> Double -> RangeMapFunc -> ControlChange
+ Sound.Tidal.MIDI.Control: NRPN :: Param -> Int -> (Int, Int) -> RangeMapFunc -> ControlChange
- Sound.Tidal.MIDI.Control: SysEx :: Param -> Int -> (Int, Int) -> Double -> RangeMapFunc -> ControlChange
+ Sound.Tidal.MIDI.Control: SysEx :: Param -> Int -> (Int, Int) -> RangeMapFunc -> ControlChange
- Sound.Tidal.MIDI.Control: mrNRPN :: Param -> Int -> (Int, Int) -> Double -> ControlChange
+ Sound.Tidal.MIDI.Control: mrNRPN :: Param -> Int -> (Int, Int) -> ControlChange
- Sound.Tidal.MIDI.Device: getDevices :: IO ([DeviceInfo])
+ Sound.Tidal.MIDI.Device: getDevices :: IO [DeviceInfo]
- Sound.Tidal.MIDI.Stream: midiDevices :: IO (MVar (MidiDeviceMap))
+ Sound.Tidal.MIDI.Stream: midiDevices :: IO (MVar MidiDeviceMap)
- Sound.Tidal.MIDI.Stream: midiSetters :: MVar (MidiDeviceMap) -> String -> Int -> ControllerShape -> IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
+ Sound.Tidal.MIDI.Stream: midiSetters :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())
Files
- Sound/Tidal/MIDI/Ambika.hs +188/−0
- Sound/Tidal/MIDI/Blofeld.hs +67/−0
- Sound/Tidal/MIDI/CC.hs +397/−0
- Sound/Tidal/MIDI/Control.hs +113/−28
- Sound/Tidal/MIDI/Device.hs +18/−3
- Sound/Tidal/MIDI/GMPerc.hs +87/−0
- Sound/Tidal/MIDI/KorgKP3.hs +17/−12
- Sound/Tidal/MIDI/MBase01.hs +34/−0
- Sound/Tidal/MIDI/MiniAtmegatron.hs +69/−0
- Sound/Tidal/MIDI/Output.hs +550/−0
- Sound/Tidal/MIDI/Stream.hs +60/−337
- Sound/Tidal/MIDI/Synth.hs +10/−9
- Sound/Tidal/MIDI/SynthParams.hs +0/−46
- Sound/Tidal/MIDI/Synthino.hs +55/−0
- Sound/Tidal/MIDI/System1M.hs +111/−59
- Sound/Tidal/MIDI/Tetra.hs +694/−0
- Sound/Tidal/MIDI/VolcaBass.hs +21/−22
- Sound/Tidal/MIDI/VolcaBeats.hs +29/−30
- Sound/Tidal/MIDI/VolcaFM.hs +39/−0
- Sound/Tidal/MIDI/VolcaKeys.hs +25/−25
- tidal-midi.cabal +15/−6
+ Sound/Tidal/MIDI/Ambika.hs view
@@ -0,0 +1,188 @@+module Sound.Tidal.MIDI.Ambika where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++ambikaController :: ControllerShape+ambikaController =+ ControllerShape+ { controls =+ [ mCC gain_p 7+ , mCC growl_p 9+ , mCC fuzz_p 12+ , mCC crush_p 13+ , mCC osc1range_p 14+ , mCC osc1detune_p 15+ , mCC osc1shape_p 16+ , mCC osc1param_p 17+ , mCC osc2shape_p 18+ , mCC osc2param_p 19+ , mCC osc2range_p 20+ , mCC osc2detune_p 21+ , mCC pan_p 22+ , mCC xmodtype_p 23+ , mCC xmodamount_p 24+ , mCC subshape_p 25+ , mCC sublevel_p 26+ , mCC noiselevel_p 27+ , mCC filtermode_p 28+ , mCC f2cutoff_p 29+ , mCC f2res_p 30+ , mCC f2mode_p 31+ , mCC lfo1sync_p 44+ , mCC lfo1rate_p 45+ , mCC lfo1shape_p 46+ , mCC lfo4rate_p 47+ , mCC lfo4shape_p 48+ , mCC lfo2sync_p 52+ , mCC lfo2rate_p 53+ , mCC lfo2shape_p 54+ , mCC lfo3sync_p 60+ , mCC lfo3rate_p 61+ , mCC lfo3shape_p 62+ , mCC hold_p 64+ , mCC legato_p 68+ , mCC env1s_p 70+ , mCC f1res_p 71+ , mCC env1r_p 72+ , mCC env1a_p 73+ , mCC f1cutoff_p 74+ , mCC env1d_p 75+ , mCC env2s_p 78+ , mCC env2r_p 80+ , mCC env2a_p 81+ , mCC env2d_p 83+ , mCC env3s_p 86+ , mCC env3r_p 88+ , mCC env3a_p 89+ , mCC env3d_p 91+ , mCC parttuning_p 94+ , mCC tuningspread_p 95+ , mCC arpmode_p 102+ , mCC arpdir_p 103+ , mCC arpoct_p 104+ , mCC arppat_p 105+ , mCC arpres_p 106+ , mCC polymode_p 107+ , mCC allsoundsoff_p 120+ , mCC resetallcontrollers_p 121+ , mCC allnotesoff_p 123+ ]+ , latency = 0.1+ }++ambikaSynth = toShape ambikaController++(growl, growl_p) = pF "growl" (Just 0)++(fuzz, fuzz_p) = pF "fuzz" (Just 0)++(acrush, acrush_p) = pF "crush" (Just 0)++(osc1range, osc1range_p) = pF "osc1range" (Just 0)++(osc1detune, osc1detune_p) = pF "osc1detune" (Just 0)++(osc1shape, osc1shape_p) = pF "osc1shape" (Just 0)++(osc1param, osc1param_p) = pF "osc1param" (Just 0)++(osc2range, osc2range_p) = pF "osc2range" (Just 0)++(osc2detune, osc2detune_p) = pF "osc2detune" (Just 0)++(osc2shape, osc2shape_p) = pF "osc2shape" (Just 0)++(osc2param, osc2param_p) = pF "osc2param" (Just 0)++(xmodtype, xmodtype_p) = pF "xmodtype" (Just 0)++(xmodamount, xmodamount_p) = pF "xmodamount" (Just 0)++(subshape, subshape_p) = pF "subshape" (Just 0)++(sublevel, sublevel_p) = pF "sublevel" (Just 0)++(noiselevel, noiselevel_p) = pF "noiselevel" (Just 0)++(filtermode, filtermode_p) = pF "filtermode" (Just 0)++(f1cutoff, f1cutoff_p) = pF "f1cutoff" (Just 0)++(f1res, f1res_p) = pF "f1res" (Just 0)++(f2cutoff, f2cutoff_p) = pF "f2cutoff" (Just 0)++(f2res, f2res_p) = pF "f2res" (Just 0)++(f2mode, f2mode_p) = pF "f2mode" (Just 0)++(lfo1sync, lfo1sync_p) = pF "lfo1sync" (Just 0)++(lfo1rate, lfo1rate_p) = pF "lfo1rate" (Just 0)++(lfo1shape, lfo1shape_p) = pF "lfo1shape" (Just 0)++(lfo2sync, lfo2sync_p) = pF "lfo2sync" (Just 0)++(lfo2rate, lfo2rate_p) = pF "lfo2rate" (Just 0)++(lfo2shape, lfo2shape_p) = pF "lfo2shape" (Just 0)++(lfo3sync, lfo3sync_p) = pF "lfo3sync" (Just 0)++(lfo3rate, lfo3rate_p) = pF "lfo3rate" (Just 0)++(lfo3shape, lfo3shape_p) = pF "lfo3shape" (Just 0)++(lfo4sync, lfo4sync_p) = pF "lfo4sync" (Just 0)++(lfo4rate, lfo4rate_p) = pF "lfo4rate" (Just 0)++(lfo4shape, lfo4shape_p) = pF "lfo4shape" (Just 0)++(env1a, env1a_p) = pF "env1a" (Just 0)++(env1d, env1d_p) = pF "env1d" (Just 0)++(env1s, env1s_p) = pF "env1s" (Just 0)++(env1r, env1r_p) = pF "env1r" (Just 0)++(env2a, env2a_p) = pF "env2a" (Just 0)++(env2d, env2d_p) = pF "env2d" (Just 0)++(env2s, env2s_p) = pF "env2s" (Just 0)++(env2r, env2r_p) = pF "env2r" (Just 0)++(env3a, env3a_p) = pF "env3a" (Just 0)++(env3d, env3d_p) = pF "env3d" (Just 0)++(env3s, env3s_p) = pF "env3s" (Just 0)++(env3r, env3r_p) = pF "env3r" (Just 0)++(arpmode, arpmode_p) = pF "arpmode" (Just 0)++(arpdir, arpdir_p) = pF "arpdir" (Just 0)++(arpoct, arpoct_p) = pF "arpoct" (Just 0)++(arppat, arppat_p) = pF "arppat" (Just 0)++(arpres, arpres_p) = pF "arpres" (Just 0)++(parttuning, parttuning_p) = pF "parttuning" (Just 0)++(tuningspread, tuningspread_p) = pF "tuningspread" (Just 0)++(polymode, polymode_p) = pF "polymode" (Just 0)++(allsoundsoff, allsoundsoff_p) = pF "allsoundsoff" (Just 0)++(allnotesoff, allnotesoff_p) = pF "allnotesoff" (Just 0)++(resetallcontrollers, resetallcontrollers_p) = pF "resetallcontrollers" (Just 0)
+ Sound/Tidal/MIDI/Blofeld.hs view
@@ -0,0 +1,67 @@+module Sound.Tidal.MIDI.Blofeld where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params hiding (octave_p, semitone_p)++bloController :: ControllerShape+bloController =+ ControllerShape+ { controls =+ [ mCC portamento_p 5+ , mCC expression_p 11+ , CC lfoshape_p 15 (0, 5) passThru -- 0..5 - sine,triangle,square,saw,random,sample&hold+ , mCC lforate_p 16+ , CC lfosync_p 17 (0, 1) passThru -- 0 off, 1 on+ , mCC lfodelay_p 18+ , CC octave_p 27 (16, 112) passThru -- 16, 28, 40 .. 112 - 128' .. 1/2'+ , CC semitone_p 28 (52, 76) passThru -- 52 .. 76 - -12 - +12 semitones+ , mCC detune_p 29+ , mCC osc1fm_p 30+ , CC osc1shape_p 31 (0, 5) passThru -- 0..5 - pulse, saw, tri, sine, alt 1, alt 2+ , mCC osc1pw_p 33+ , mCC osc1pwm_p 34+ , mCC osc1vol_p 52+ , mCC osc1pan_p 53+ , mCC ringmod_p 54+ , mCC ringpan_p 55+ , mCC noise_p 60+ , mCC noisepan_p 61+ , mCC noisecol_p 62+ , mCC cutoff_p 69+ , mCC attack_p 101+ , mCC decay_p 102+ , mCC sustain_p 103+ , mCC release_p 106+ ]+ , latency = 0.1+ }++blofeld = toShape bloController++(_, octave_p) = pF "octave" (Just 0)++(_, semitone_p) = pF "semitone" (Just 0.5)++(lforate, lforate_p) = pF "lforate" (Just 0)++(osc1fm, osc1fm_p) = pF "osc1fm" (Just 0)++(osc1shape, osc1shape_p) = pF "osc1shape" (Just 0)++(osc1pw, osc1pw_p) = pF "osc1pw" (Just 0)++(osc1pwm, osc1pwm_p) = pF "osc1pwm" (Just 0)++(osc1vol, osc1vol_p) = pF "osc1vol" (Just 0)++(osc1pan, osc1pan_p) = pF "osc1pan" (Just 0)++(ringmod, ringmod_p) = pF "ringmod" (Just 0)++(ringpan, ringpan_p) = pF "ringpan" (Just 0)++(noise, noise_p) = pF "noise" (Just 0)++(noisepan, noisepan_p) = pF "noisepan" (Just 0)++(noisecol, noisecol_p) = pF "noisecol" (Just 0)
+ Sound/Tidal/MIDI/CC.hs view
@@ -0,0 +1,397 @@+module Sound.Tidal.MIDI.CC where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++ccallController :: ControllerShape+ccallController =+ ControllerShape+ { controls =+ [ mCC cc0_p 0+ , mCC cc1_p 1+ , mCC cc2_p 2+ , mCC cc3_p 3+ , mCC cc4_p 4+ , mCC cc5_p 5+ , mCC cc6_p 6+ , mCC cc7_p 7+ , mCC cc8_p 8+ , mCC cc9_p 9+ , mCC cc10_p 10+ , mCC cc11_p 11+ , mCC cc12_p 12+ , mCC cc13_p 13+ , mCC cc14_p 14+ , mCC cc15_p 15+ , mCC cc16_p 16+ , mCC cc17_p 17+ , mCC cc18_p 18+ , mCC cc19_p 19+ , mCC cc20_p 20+ , mCC cc21_p 21+ , mCC cc22_p 22+ , mCC cc23_p 23+ , mCC cc24_p 24+ , mCC cc25_p 25+ , mCC cc26_p 26+ , mCC cc27_p 27+ , mCC cc28_p 28+ , mCC cc29_p 29+ , mCC cc30_p 30+ , mCC cc31_p 31+ , mCC cc32_p 32+ , mCC cc33_p 33+ , mCC cc34_p 34+ , mCC cc35_p 35+ , mCC cc36_p 36+ , mCC cc37_p 37+ , mCC cc38_p 38+ , mCC cc39_p 39+ , mCC cc40_p 40+ , mCC cc41_p 41+ , mCC cc42_p 42+ , mCC cc43_p 43+ , mCC cc44_p 44+ , mCC cc45_p 45+ , mCC cc46_p 46+ , mCC cc47_p 47+ , mCC cc48_p 48+ , mCC cc49_p 49+ , mCC cc50_p 50+ , mCC cc51_p 51+ , mCC cc52_p 52+ , mCC cc53_p 53+ , mCC cc54_p 54+ , mCC cc55_p 55+ , mCC cc56_p 56+ , mCC cc57_p 57+ , mCC cc58_p 58+ , mCC cc59_p 59+ , mCC cc60_p 60+ , mCC cc61_p 61+ , mCC cc62_p 62+ , mCC cc63_p 63+ , mCC cc64_p 64+ , mCC cc65_p 65+ , mCC cc66_p 66+ , mCC cc67_p 67+ , mCC cc68_p 68+ , mCC cc69_p 69+ , mCC cc70_p 70+ , mCC cc71_p 71+ , mCC cc72_p 72+ , mCC cc73_p 73+ , mCC cc74_p 74+ , mCC cc75_p 75+ , mCC cc76_p 76+ , mCC cc77_p 77+ , mCC cc78_p 78+ , mCC cc79_p 79+ , mCC cc80_p 80+ , mCC cc81_p 81+ , mCC cc82_p 82+ , mCC cc83_p 83+ , mCC cc84_p 84+ , mCC cc85_p 85+ , mCC cc86_p 86+ , mCC cc87_p 87+ , mCC cc89_p 89+ , mCC cc90_p 90+ , mCC cc91_p 91+ , mCC cc92_p 92+ , mCC cc93_p 93+ , mCC cc94_p 94+ , mCC cc95_p 95+ , mCC cc96_p 96+ , mCC cc97_p 97+ , mCC cc98_p 98+ , mCC cc99_p 99+ , mCC cc100_p 100+ , mCC cc101_p 101+ , mCC cc102_p 102+ , mCC cc103_p 103+ , mCC cc104_p 104+ , mCC cc105_p 105+ , mCC cc106_p 106+ , mCC cc107_p 107+ , mCC cc108_p 108+ , mCC cc109_p 109+ , mCC cc110_p 110+ , mCC cc111_p 111+ , mCC cc112_p 112+ , mCC cc113_p 113+ , mCC cc114_p 114+ , mCC cc115_p 115+ , mCC cc116_p 116+ , mCC cc117_p 117+ , mCC cc118_p 118+ , mCC cc119_p 119+ , mCC cc120_p 120+ , mCC cc121_p 121+ , mCC cc122_p 122+ , mCC cc123_p 123+ , mCC cc124_p 124+ , mCC cc125_p 125+ , mCC cc126_p 126+ , mCC cc127_p 127+ ]+ , latency = 0.1+ }++ccall = toShape ccallController++(cc0, cc0_p) = pF "cc0" (Just 0)++(cc1, cc1_p) = pF "cc1" (Just 0)++(cc2, cc2_p) = pF "cc2" (Just 0)++(cc3, cc3_p) = pF "cc3" (Just 0)++(cc4, cc4_p) = pF "cc4" (Just 0)++(cc5, cc5_p) = pF "cc5" (Just 0)++(cc6, cc6_p) = pF "cc6" (Just 0)++(cc7, cc7_p) = pF "cc7" (Just 0)++(cc8, cc8_p) = pF "cc8" (Just 0)++(cc9, cc9_p) = pF "cc9" (Just 0)++(cc10, cc10_p) = pF "cc10" (Just 0)++(cc11, cc11_p) = pF "cc11" (Just 0)++(cc12, cc12_p) = pF "cc12" (Just 0)++(cc13, cc13_p) = pF "cc13" (Just 0)++(cc14, cc14_p) = pF "cc14" (Just 0)++(cc15, cc15_p) = pF "cc15" (Just 0)++(cc16, cc16_p) = pF "cc16" (Just 0)++(cc17, cc17_p) = pF "cc17" (Just 0)++(cc18, cc18_p) = pF "cc18" (Just 0)++(cc19, cc19_p) = pF "cc19" (Just 0)++(cc20, cc20_p) = pF "cc20" (Just 0)++(cc21, cc21_p) = pF "cc21" (Just 0)++(cc22, cc22_p) = pF "cc22" (Just 0)++(cc23, cc23_p) = pF "cc23" (Just 0)++(cc24, cc24_p) = pF "cc24" (Just 0)++(cc25, cc25_p) = pF "cc25" (Just 0)++(cc26, cc26_p) = pF "cc26" (Just 0)++(cc27, cc27_p) = pF "cc27" (Just 0)++(cc28, cc28_p) = pF "cc28" (Just 0)++(cc29, cc29_p) = pF "cc29" (Just 0)++(cc30, cc30_p) = pF "cc30" (Just 0)++(cc31, cc31_p) = pF "cc31" (Just 0)++(cc32, cc32_p) = pF "cc32" (Just 0)++(cc33, cc33_p) = pF "cc33" (Just 0)++(cc34, cc34_p) = pF "cc34" (Just 0)++(cc35, cc35_p) = pF "cc35" (Just 0)++(cc36, cc36_p) = pF "cc36" (Just 0)++(cc37, cc37_p) = pF "cc37" (Just 0)++(cc38, cc38_p) = pF "cc38" (Just 0)++(cc39, cc39_p) = pF "cc39" (Just 0)++(cc40, cc40_p) = pF "cc40" (Just 0)++(cc41, cc41_p) = pF "cc41" (Just 0)++(cc42, cc42_p) = pF "cc42" (Just 0)++(cc43, cc43_p) = pF "cc43" (Just 0)++(cc44, cc44_p) = pF "cc44" (Just 0)++(cc45, cc45_p) = pF "cc45" (Just 0)++(cc46, cc46_p) = pF "cc46" (Just 0)++(cc47, cc47_p) = pF "cc47" (Just 0)++(cc48, cc48_p) = pF "cc48" (Just 0)++(cc49, cc49_p) = pF "cc49" (Just 0)++(cc50, cc50_p) = pF "cc50" (Just 0)++(cc51, cc51_p) = pF "cc51" (Just 0)++(cc52, cc52_p) = pF "cc52" (Just 0)++(cc53, cc53_p) = pF "cc53" (Just 0)++(cc54, cc54_p) = pF "cc54" (Just 0)++(cc55, cc55_p) = pF "cc55" (Just 0)++(cc56, cc56_p) = pF "cc56" (Just 0)++(cc57, cc57_p) = pF "cc57" (Just 0)++(cc58, cc58_p) = pF "cc58" (Just 0)++(cc59, cc59_p) = pF "cc59" (Just 0)++(cc60, cc60_p) = pF "cc60" (Just 0)++(cc61, cc61_p) = pF "cc61" (Just 0)++(cc62, cc62_p) = pF "cc62" (Just 0)++(cc63, cc63_p) = pF "cc63" (Just 0)++(cc64, cc64_p) = pF "cc64" (Just 0)++(cc65, cc65_p) = pF "cc65" (Just 0)++(cc66, cc66_p) = pF "cc66" (Just 0)++(cc67, cc67_p) = pF "cc67" (Just 0)++(cc68, cc68_p) = pF "cc68" (Just 0)++(cc69, cc69_p) = pF "cc69" (Just 0)++(cc70, cc70_p) = pF "cc70" (Just 0)++(cc71, cc71_p) = pF "cc71" (Just 0)++(cc72, cc72_p) = pF "cc72" (Just 0)++(cc73, cc73_p) = pF "cc73" (Just 0)++(cc74, cc74_p) = pF "cc74" (Just 0)++(cc75, cc75_p) = pF "cc75" (Just 0)++(cc76, cc76_p) = pF "cc76" (Just 0)++(cc77, cc77_p) = pF "cc77" (Just 0)++(cc78, cc78_p) = pF "cc78" (Just 0)++(cc79, cc79_p) = pF "cc79" (Just 0)++(cc80, cc80_p) = pF "cc80" (Just 0)++(cc81, cc81_p) = pF "cc81" (Just 0)++(cc82, cc82_p) = pF "cc82" (Just 0)++(cc83, cc83_p) = pF "cc83" (Just 0)++(cc84, cc84_p) = pF "cc84" (Just 0)++(cc85, cc85_p) = pF "cc85" (Just 0)++(cc86, cc86_p) = pF "cc86" (Just 0)++(cc87, cc87_p) = pF "cc87" (Just 0)++(cc88, cc88_p) = pF "cc88" (Just 0)++(cc89, cc89_p) = pF "cc89" (Just 0)++(cc90, cc90_p) = pF "cc90" (Just 0)++(cc91, cc91_p) = pF "cc91" (Just 0)++(cc92, cc92_p) = pF "cc92" (Just 0)++(cc93, cc93_p) = pF "cc93" (Just 0)++(cc94, cc94_p) = pF "cc94" (Just 0)++(cc95, cc95_p) = pF "cc95" (Just 0)++(cc96, cc96_p) = pF "cc96" (Just 0)++(cc97, cc97_p) = pF "cc97" (Just 0)++(cc98, cc98_p) = pF "cc98" (Just 0)++(cc99, cc99_p) = pF "cc99" (Just 0)++(cc100, cc100_p) = pF "cc100" (Just 0)++(cc101, cc101_p) = pF "cc101" (Just 0)++(cc102, cc102_p) = pF "cc102" (Just 0)++(cc103, cc103_p) = pF "cc103" (Just 0)++(cc104, cc104_p) = pF "cc104" (Just 0)++(cc105, cc105_p) = pF "cc105" (Just 0)++(cc106, cc106_p) = pF "cc106" (Just 0)++(cc107, cc107_p) = pF "cc107" (Just 0)++(cc108, cc108_p) = pF "cc108" (Just 0)++(cc109, cc109_p) = pF "cc109" (Just 0)++(cc110, cc110_p) = pF "cc110" (Just 0)++(cc111, cc111_p) = pF "cc111" (Just 0)++(cc112, cc112_p) = pF "cc112" (Just 0)++(cc113, cc113_p) = pF "cc113" (Just 0)++(cc114, cc114_p) = pF "cc114" (Just 0)++(cc115, cc115_p) = pF "cc115" (Just 0)++(cc116, cc116_p) = pF "cc116" (Just 0)++(cc117, cc117_p) = pF "cc117" (Just 0)++(cc118, cc118_p) = pF "cc118" (Just 0)++(cc119, cc119_p) = pF "cc119" (Just 0)++(cc120, cc120_p) = pF "cc120" (Just 0)++(cc121, cc121_p) = pF "cc121" (Just 0)++(cc122, cc122_p) = pF "cc122" (Just 0)++(cc123, cc123_p) = pF "cc123" (Just 0)++(cc124, cc124_p) = pF "cc124" (Just 0)++(cc125, cc125_p) = pF "cc125" (Just 0)++(cc126, cc126_p) = pF "cc126" (Just 0)++(cc127, cc127_p) = pF "cc127" (Just 0)
Sound/Tidal/MIDI/Control.hs view
@@ -1,74 +1,159 @@+{- |+Mappings between Tidal's 'Sound.Tidal.Stream.Param's and MIDI control changes+-} module Sound.Tidal.MIDI.Control where +import Control.Applicative ((<$>)) import qualified Sound.Tidal.Stream as S+import Sound.Tidal.Tempo (Tempo(cps))+import qualified Data.Map.Strict as Map+import Data.Ratio+import Sound.Tidal.Params hiding (n_p) -import Sound.Tidal.Params+n_p :: S.Param+n_p = snd $ pI "n" (Just 128) +{-|+Map a 'Double' to 'Int' using given min/max values+-} type RangeMapFunc = (Int, Int) -> Double -> Int +{- | Make sure you apply @cutShape midiShape@ to an 'Sound.Tidal.Stream.ParamMap'+before passing it into a function wanting this type -}+type MIDINoteShape = S.ParamMap++{-|+Describe mapping a Tidal 'Sound.Tidal.Stream.Param' in terms of MIDI+-} data ControlChange =- CC { param :: S.Param,- midi :: Int,- range :: (Int, Int),- vdefault :: Double,- scalef :: RangeMapFunc+ CC { param :: S.Param, -- ^ the 'Sound.Tidal.Stream.Param' this control will apply to+ midi :: Int, -- ^ the MIDI parameter number to map to+ range :: (Int, Int), -- ^ the range this MIDI parameter accepts, by default this is (0,127)+ scalef :: RangeMapFunc -- ^ the function to apply mapping floating point values from pattern to MIDI integer values } | NRPN { param :: S.Param, midi :: Int, range :: (Int, Int),- vdefault :: Double, scalef :: RangeMapFunc } | SysEx { param :: S.Param, midi :: Int, range :: (Int, Int),- vdefault :: Double, scalef :: RangeMapFunc } +{- |+A definition for using a Tidal with specific MIDI device type.++By default, every 'ControllerShape' accepts the following 'Sound.Tidal.Stream.Param's:++* 'Sound.Tidal.Params.dur'+* 'Sound.Tidal.Params.n'+* 'Sound.Tidal.Params.velocity'+* 'Sound.Tidal.Params.nudge'+* 'Sound.Tidal.Params.unit'++which will define the MIDI note to be played.+-} data ControllerShape = ControllerShape {- controls :: [ControlChange],- latency :: Double+ controls :: [ControlChange], -- ^ a list of controls that can be understood by a certain device type+ latency :: Double -- ^ the latency to be used when sending out MIDI messages, this is passed to 'Sound.Tidal.Stream.Shape' } +{- |+A simple shape defining the 'Sound.Tidal.Stream.Param's that are used for generating MIDI notes. +This simplifies splitting a 'Sound.Tidal.Stream.ParamMap' into params for notes and control values.+-}+midiShape :: S.Shape+midiShape = S.Shape {+ S.params = [ + dur_p,+ n_p,+ nudge_p,+ velocity_p, + unit_p+ ],+ S.latency = 0,+ S.cpsStamp = False+ }++{- |+Turns a 'MIDINoteShape' into concrete values for scheduling.++-}+computeTiming :: Tempo -- ^ the current playback speed+ -> Ratio Integer {- ^ if 'Sound.Tidal.Params.unit' is specified as @cycle@,+this will be utilized to calculate the note's absolute duration with regard to current cycle length __Note__: this will ignore the specified duration of the Tidal param 'Sound.Tidal.Params.dur' -}+ -> MIDINoteShape -- ^ A map of 'Sound.Tidal.Stream.Param's that describes the note to be played+ -> ((Int,Int,Ratio Integer), Double) -- ^ A tuple of a 'Sound.Tidal.MIDI.Output.TimedNote' triplet and the value for 'nudge' to offset this note by+computeTiming tempo duration note' = ((n', v', d'), nudge')+ where+ unit' = S.svalue $ note' Map.! unit_p + v' = mapRange (0, 127) $ S.fvalue $ note' Map.! velocity_p+ n' = S.ivalue $ note' Map.! n_p+ d' = case unit' of+ "rate" -> byRate+ "cycle" -> (+) (-0.001) $ (/) duration $ realToFrac $ cps tempo+ _ -> byRate+ byRate = realToFrac $ S.fvalue $ note' Map.! dur_p++ nudge' = S.fvalue $ note' Map.! nudge_p++{- | Converts a 'ControllerShape's controls into 'Sound.Tidal.Stream.Param's and makes a 'Sound.Tidal.Stream.Shape'+This acts as an interface between Tidal's scheduling loop and MIDI scheduling. -} toShape :: ControllerShape -> S.Shape-toShape cs =- let params = [dur_p, n_p, velocity_p] ++ params'- params' = [param p | p <- (controls cs)]- in S.Shape { S.params = params,- S.cpsStamp = False,- S.latency = latency cs- }+toShape cs = S.Shape {+ S.params = toParams cs,+ S.cpsStamp = False,+ S.latency = latency cs+ } +{- | A 'RangeMapFunc' that simply passes 'floor's 'Double's.++This can be used if a MIDI parameter of a device has different meanings for each value,+e.g. the type of oscillator has to be specified by either "0", "1", "2" or "3" each representing a different waveform (sine, tri, square, rand)+-} passThru :: (Int, Int) -> Double -> Int passThru (_, _) = floor -- no sanitizing of range… +{- | Default mapping function from Double to Int.++>>> mapRange (0, 127) 0.5+63+-} mapRange :: (Int, Int) -> Double -> Int-mapRange (low, high) = floor . (+ (fromIntegral low)) . (* ratio)+mapRange (low, high) = floor . (+ fromIntegral low) . (* ratio) where ratio = fromIntegral $ high - low +-- | Helper function for creating a standard ControlChange for MIDI parameter mCC :: S.Param -> Int -> ControlChange-mCC p m = CC {param=p, midi=m, range=(0, 127), vdefault=0, scalef=mapRange }+mCC p m = CC {param=p, midi=m, range=(0, 127), scalef=mapRange } +-- | Helper function for creating a standard ControlChange for a non-registered MIDI parameter mNRPN :: S.Param -> Int -> ControlChange-mNRPN p m = NRPN {param=p, midi=m, range=(0, 127), vdefault=0, scalef=mapRange }+mNRPN p m = NRPN {param=p, midi=m, range=(0, 127), scalef=mapRange } -mrNRPN :: S.Param -> Int -> (Int, Int) -> Double -> ControlChange-mrNRPN p m r d = NRPN {param=p, midi=m, range=r, vdefault=d, scalef=mapRange }+-- | Helper function for creating a ControlChange for a non-registered MIDI parameter with a custom range+mrNRPN :: S.Param -> Int -> (Int, Int) -> ControlChange+mrNRPN p m r = NRPN {param=p, midi=m, range=r, scalef=mapRange } +-- | Translate a 'ControllerShape's controls into a list of 'Sound.Tidal.Stream.Param' toParams :: ControllerShape -> [S.Param]-toParams shape = map param (controls shape)+toParams shape' = map param (controls shape') +{- | Translate a Tidal 'Sound.Tidal.Stream.Param' into the corresponding MIDI parameter number+according to a specific 'ControllerShape' -} ctrlN :: Num b => ControllerShape -> S.Param -> Maybe b-ctrlN shape x = fmap fromIntegral $ fmap midi (paramN shape x)+ctrlN shape' x = (fromIntegral . midi) <$> (paramN shape' x) +-- | Find the first 'ControlChange' that uses 'Sound.Tidal.Stream.Param' paramN :: ControllerShape -> S.Param -> Maybe ControlChange-paramN shape x+paramN shape' x | x `elem` names = paramX $ matching p- | otherwise = Nothing -- error $ "No such Controller param: " ++ show x- where names = toParams shape+ | otherwise = Nothing+ where names = toParams shape' paramX [] = Nothing paramX (h:_) = Just h matching = filter ((== x) . param)- p = controls shape+ p = controls shape'
Sound/Tidal/MIDI/Device.hs view
@@ -1,17 +1,30 @@+{-# OPTIONS_HADDOCK not-home #-}+{-|+Convenience functions to access "Sound.PortMidi" devices.+-} module Sound.Tidal.MIDI.Device where import qualified Sound.PortMidi as PM +{-| Example usage:++>>> putStrLn =<< displayOutputDevices+ID: Name+0: Midi Through Port-0+2: DSI Tetra MIDI 1++-} displayOutputDevices :: IO String displayOutputDevices = do devices <- getIndexedDevices return $ displayDevices $ getOutputDevices devices +-- | Readable version of a list of indexed MIDI devices displayDevices :: Show a => [(a, PM.DeviceInfo)] -> String displayDevices devices = let indices = map (show . fst) devices names = map ((":\t"++) . PM.name . snd) devices pairs = zipWith (++) indices names- in unlines (["ID:\tName"]++pairs)+ in unlines ("ID:\tName" : pairs) getOutputDevices :: [(a, PM.DeviceInfo)] -> [(a, PM.DeviceInfo)] getOutputDevices = filter (PM.output . snd)@@ -21,9 +34,9 @@ rawDevices <- getDevices return $ zip [0..] rawDevices -getDevices :: IO ([PM.DeviceInfo])+getDevices :: IO [PM.DeviceInfo] getDevices = do- PM.initialize+ _ <- PM.initialize count <- PM.countDevices mapM PM.getDeviceInfo [0..(count - 1)] @@ -34,3 +47,5 @@ case res of [] -> return Nothing [dev] -> return $ Just $ fromIntegral $ fst dev++
+ Sound/Tidal/MIDI/GMPerc.hs view
@@ -0,0 +1,87 @@+module Sound.Tidal.MIDI.GMPerc where++import Control.Applicative+import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++gmpercController :: ControllerShape+gmpercController =+ ControllerShape+ { controls = [mCC balance_p 10, mCC reverb_p 91, mCC chorus_p 93]+ , latency = 0.1+ }++perc = midinote . (percN <$>)++percN :: String -> Int+percN "hq" = 27+percN "sl" = 28+percN "sps" = 29+percN "spl" = 30+percN "st" = 31+percN "sqc" = 32+percN "mcl" = 33+percN "mb" = 34+percN "abd" = 35+percN "bd" = 36+percN "sti" = 37+percN "sn" = 38+percN "cp" = 39+percN "esn" = 40+percN "lft" = 41+percN "ch" = 42+percN "hft" = 43+percN "hh" = 44+percN "lt" = 45+percN "oh" = 46+percN "lmt" = 47+percN "hmt" = 48+percN "cr" = 49+percN "ht" = 50+percN "ri" = 51+percN "cy" = 52+percN "be" = 53+percN "ta" = 54+percN "scy" = 55+percN "cow" = 56+percN "cr2" = 57+percN "vib" = 58+percN "ri2" = 59+percN "hb" = 60+percN "lb" = 61+percN "mhc" = 62+percN "ohc" = 63+percN "lc" = 64+percN "hti" = 65+percN "lti" = 66+percN "hag" = 67+percN "lag" = 68+percN "ca" = 69+percN "ma" = 70+percN "shi" = 71+percN "lhi" = 72+percN "sgui" = 73+percN "lgui" = 74+percN "cl" = 75+percN "hwb" = 76+percN "lwb" = 77+percN "mc" = 78+percN "oc" = 79+percN "mt" = 80+percN "ot" = 81+percN "sha" = 82+percN "jb" = 83+percN "bt" = 84+percN "cas" = 85+percN "ms" = 86+percN "os" = 87+percN _ = 0++-- general shape for stream+gmperc = toShape gmpercController++(balance, balance_p) = pF "balance" (Just 0)++(reverb, reverb_p) = pF "reverb" (Just 0)++(chorus, chorus_p) = pF "chorus" (Just 0)
Sound/Tidal/MIDI/KorgKP3.hs view
@@ -5,24 +5,29 @@ import Sound.Tidal.MIDI.Control kp3 :: ControllerShape-kp3 = ControllerShape { controls = [- mCC xaxis_p 12,- mCC yaxis_p 13,- mCC padon_p 92,- mCC level_p 93,- mCC fxdepth_p 94,- mCC holdbut_p 95- ],- -- duration = ("dur", 0.05),- -- velocity = ("vel", 0.5),- latency = 0.1- }+kp3 =+ ControllerShape+ { controls =+ [ mCC xaxis_p 12+ , mCC yaxis_p 13+ , mCC padon_p 92+ , mCC level_p 93+ , mCC fxdepth_p 94+ , mCC holdbut_p 95+ ]+ , latency = 0.1+ } oscKp3 = toShape kp3 (xaxis, xaxis_p) = pF "xaxis" (Just 0)+ (yaxis, yaxis_p) = pF "yaxis" (Just 0)+ (padon, padon_p) = pF "padon" (Just 0)+ (level, level_p) = pF "level" (Just 0)+ (fxdepth, fxdepth_p) = pF "fxdepth" (Just 0)+ (holdbut, holdbut_p) = pF "holdbut" (Just 0)
+ Sound/Tidal/MIDI/MBase01.hs view
@@ -0,0 +1,34 @@+module Sound.Tidal.MIDI.MBase01 where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++mbase01Controller :: ControllerShape+mbase01Controller =+ ControllerShape+ { controls =+ [ mCC tune_p 100+ , mCC pitch_p 101+ , mCC decay_p 102+ , mCC harmonics_p 103+ , mCC pulse_p 104+ , mCC noise_p 105+ , mCC attack_p 106+ , mCC eqlzr_p 107+ ]+ , latency = 0.1+ }++mbase01 = toShape mbase01Controller++(tune, tune_p) = pF "tune" (Just 0)++(pitch, pitch_p) = pF "pitch" (Just 0)++(harmonics, harmonics_p) = pF "harmonics" (Just 0)++(pulse, pulse_p) = pF "pulse" (Just 0)++(noise, noise_p) = pF "noise" (Just 0)++(eqlzr, eqlzr_p) = pF "eqlzr" (Just 0)
+ Sound/Tidal/MIDI/MiniAtmegatron.hs view
@@ -0,0 +1,69 @@+{-|+miniAtmegatron - Soulsby Synthesizers++http://soulsbysynths.com/wp-content/uploads/2016/08/Mini-Manual.pdf, page 15++-}+module Sound.Tidal.MIDI.MiniAtmegatron where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++matmController :: ControllerShape+matmController =+ ControllerShape+ { controls =+ [ mCC modwheel_p 1+ , mCC pan_p 10+ , mCC expression_p 11+ , mCC sustainpedal_p 64+ , mCC cutoff_p 74+ , mCC filtenv_p 16+ , mCC flfo_p 93+ , mCC alfo_p 92+ , mCC shape_p 17+ , mCC resonance_p 71+ , mCC penv_p 94+ , mCC plfo_p 1+ , mCC pwm_p 91+ , mCC flange_p 95+ , mCC fwave_p 30+ , mCC ffilt_p 31+ , mCC ffenv_p 32+ , mCC faenv_p 33+ , mCC mlfoshape_p 34+ , mCC lfospeed_p 79+ , mCC porta_p 5+ ]+ , latency = 0.1+ }++matm = toShape matmController++(fen, filtenv_p) = pF "fen" (Just 0)++(flo, flfo_p) = pF "flo" (Just 0)++(alo, alfo_p) = pF "alo" (Just 0)++(pen, penv_p) = pF "pen" (Just 0)++(plo, plfo_p) = pF "plo" (Just 0)++(pwm, pwm_p) = pF "pwm" (Just 0)++(fln, flange_p) = pF "fln" (Just 0)++(fwv, fwave_p) = pF "fwv" (Just 0)++(ffl, ffilt_p) = pF "ffl" (Just 0)++(ffe, ffenv_p) = pF "ffe" (Just 0)++(fae, faenv_p) = pF "fae" (Just 0)++(lfs, mlfoshape_p) = pF "lfs" (Just 0)++(lss, lfospeed_p) = pF "lss" (Just 0)++(por, porta_p) = pF "por" (Just 0)
+ Sound/Tidal/MIDI/Output.hs view
@@ -0,0 +1,550 @@+{-# OPTIONS_HADDOCK not-home #-}+{-|+A bridge between evaluated Tidal patterns and MIDI events.++This module contains functions necessary to mediate between+'Sound.Tidal.Time.Event's generated from a Tidal 'Sound.Tidal.Pattern.Pattern'+and plain MIDI events sent through 'Sound.PortMidi.PMStream'.+-}+module Sound.Tidal.MIDI.Output (+ -- * Types+ Output(..),+ OutputState,+ MidiDeviceMap,+ TimedNote,+ -- * Initialization+ makeConnection,+ flushBackend,+ -- * Scheduling+ sendevents,+ store,+ mkStore,+ storeParams,+ scheduleTime,+ -- * Converters+ toMidiValue,+ cutShape,+ stripDefaults,+ -- * State handling+ changeState,+ readState,+ -- * Low-level functions+ useOutput,+ displayOutputDevices,+ outputDevice,+ makeRawEvent,+ noteOn,+ noteOff,+ makeCtrl+ ) where++-- generics+import Control.Applicative ((<$>), (<*>), pure)+import Control.Monad+import Control.Concurrent+import Control.Concurrent.MVar ()+import Data.Bits+import Data.List (sortBy, find, partition)+import qualified Data.Map as Map+import Data.Maybe+import Data.Ord (comparing)+import Data.Ratio (Ratio)+import Data.Time (getCurrentTime, UTCTime)+import Data.Time.Clock.POSIX+import Foreign.C+import Numeric++-- Tidal specific+import Sound.Tidal.Tempo (Tempo(Tempo))+import Sound.Tidal.Stream as S++-- MIDI specific+import Sound.Tidal.MIDI.Device+import Sound.Tidal.MIDI.Control+import qualified Sound.PortMidi as PM++type ConnectionCount = Int+type TickedConnectionCount = Int+type OutputOnline = Bool+{- |+Keep track of virtual streams++* Reflects the number of virtual streams that have already stored their events for this tick. Every time 'TickedConnectionCount' cycles, MIDI events will be sent out.+* 'ConnectionCount' is increased on every new stream created via `midiSetters`+* For each channel, currently used params and their values are kept.+* Output will only be scheduling, once __online__, i.e. when the first stream is initialized+-}+type OutputState = (+ TickedConnectionCount, + ConnectionCount,+ [ParamMap], + OutputOnline + )++type Tick = Int+type Onset = Double+type Offset = Double+type RelativeOffset = Double+type MIDITime = (Tempo, Tick, Onset, RelativeOffset)+type MIDIEvent = (MIDITime, MIDIMessage)+type MIDIChannel = CLong+type MIDIStatus = CLong+type MIDINote = MIDIDatum+type MIDIVelocity = MIDIDatum+type MIDIDatum = CLong+type MIDIDuration = Ratio Integer+type MIDIMessage = (MIDIChannel, MIDIStatus, MIDINote, MIDIVelocity)+-- | A Triplet of the deviation from the note @a5@, velocity and duration+type TimedNote = (CLong, MIDIVelocity, MIDIDuration)+type SentEvent = (CULong, Double, PM.PMEvent, CULong, UTCTime)+{-|+An abstract definition of a physical MIDI Output.++Manages virtual streams to multiple channels of a single connection to a MIDI device.+-}+data Output = Output {+ cshape :: ControllerShape, -- ^ The ControllerShape defining which 'Param's will be available for use+ conn :: PM.PMStream, -- ^ The physical connection to the device, uses 'PortMidi'+ buffer :: MVar ([ParamMap], [MIDIEvent]), -- ^ A buffer of currently used 'Param's and their 'Value's as well as a list of 'MIDIEvent's to be sent on the next tick.+ bufferstate :: MVar OutputState, -- ^ Keeps track of connected virtual streams during one tick+ midistart :: CULong, -- ^ the MIDI time when this output was created+ rstart :: UTCTime -- ^ the real time when this output was created+ }++type MidiMap = Map.Map S.Param (Maybe Int)+type MidiDeviceMap = Map.Map String Output+++-- | Initialize a connection to the given MIDI device by Name+makeConnection :: MVar MidiDeviceMap -- ^ The current list of already connected devices+ -> String -- ^ The MIDI device name+ -> Int -- ^ The MIDI channel+ -> ControllerShape -- ^ The definition of useable 'Control's+ -> IO (S.ToMessageFunc, Output) -- ^ A function to schedule MIDI events and the output that keeps track of connections+makeConnection devicesM displayname channel controllershape = do+ moutput <- useOutput devicesM displayname controllershape+ case moutput of+ Just o -> do+ s <- connected channel displayname o+ return (s, o)+ Nothing ->+ error "Failed initializing MIDI connection"+++{- |+Sends out MIDI events once all virtual streams have buffered their events.++This will be called after every tick+-}+flushBackend :: Output -> S.Shape -> Tempo -> Int -> IO ()+flushBackend o shape change ticks = do+ changeState tickConnections o+ cycling <- readState isCycling o++ Control.Monad.when cycling (do+ -- gather last sent params, update state with new+ let buf = buffer o+ (states, events) <- takeMVar buf++ ((_,_,newstates,_), (_,_,oldstates,_)) <- changeState' (resetParamStates states) o++ -- find params that were removed+ let mapDefaults = Map.mapWithKey (\k _ -> defaultValue k)+ diffs = map mapDefaults $ zipWith Map.difference oldstates newstates+ -- store additional "reset" events in buffer+ -- schedule time must be exactly before/ontime with the next regular event to be sent. otherwise we risk+ -- mixing order of ctrl messages, and resets get overridden+ -- FIXME: when scheduling, note late CC messages and DROP THEM, otherwise everything is screwed+ let offset = S.latency shape+ mididiffs = map ((toMidiMap (cshape o)).(stripShape (toShape $ cshape o))) $ diffs + resetevents = concat $ zipWith (\x y -> makectrls o x (change,ticks,1,offset) y) [1..] mididiffs++ -- send out MIDI events+ (late, later) <- sendevents o shape change ticks events resetevents+ -- finally clear buffered ParamMap for next tick+ putMVar buf (replicate 16 Map.empty, later)+ let len = length late+ case len of+ 0 ->+ return ()+ _ -> do+ putStrLn $ showLate $ head late+ putStrLn $ "and " ++ show (len - 1) ++ " more")+++-- Scheduling++{- |+Sends out MIDI events due for this tick.+-}+sendevents :: Output -- ^ The connection to be used+ -> S.Shape -- ^ The shape to be queried for latency+ -> Tempo -- ^ The current speed+ -> Tick -- ^ The number of ticks elapsed since start, may be reset when using @cps (-1)@+ -> [MIDIEvent] -- ^ A list of events potentially needed to be sent+ -> [MIDIEvent] -- ^ A list of reset events potentially needed to be sent+ -> IO ([SentEvent], [MIDIEvent]) -- ^ A list of events sent late and a list of events to send later+sendevents _ _ _ _ [] [] = return ([],[])+sendevents s shape change ticks evts resets = do+ -- assumptions:+ -- all reset events have the same timestamp+ -- questions: + -- could there be any events in `evts` at all that need reset? or are these just in late from the last tick?+ let output = conn s+ toDescriptor midiTime now (o,_,t,e) = (o,t,e, midiTime, now)+ calcOnsets (a@(tempo, tick, onset, offset), e) = (a, logicalOnset' tempo tick onset offset, e)++ midiTime <- PM.time+ now <- getCurrentTime+ let offset = S.latency shape+ nextTick = logicalOnset' change (ticks+1) 0 offset+ mkEvent (t, o, e) = (midionset, t, o, makeRawEvent e midionset)+ where midionset = scheduleTime (midistart s, rstart s) o + onsets = map calcOnsets evts+ -- calculate temporary scheduling for resetevts+ resetevts = map calcOnsets resets+ -- split into events sent now and later (e.g. a noteOff that would otherwise cut off noteOn's in the next tick)+ (evts', later) = span ((< nextTick).(\(_,o,_) -> o)) $ sortBy (comparing (\(_,o,_) -> o)) onsets+ -- calculate MIDI time to schedule events, putting time into fn to create PM.PMEvents+ evts'' = map mkEvent evts'+ -- a list CC `names` that need to be reset+ resetccs = map (\(_, _, (_, _, d1, _)) -> d1) resetevts+ later' = map (\(t,_,e) -> (t,e)) later+ findCC match list = find (\(_, _, (_, st, d1, _)) -> st == 0xB0 && (d1 `elem` match)) $ reverse list+++ -- 1. find the ccs that needs reset (search in `later` then in `evts`)+ (evtstosend, laterevts) = case findCC resetccs later of+ Nothing -> case findCC resetccs evts' of+ -- 1c. no events at all need to be reset+ -- 1cI. use the default passed in midionset for resets+ -- 1cII. append `resets` to `evts` FIXME: make sure we really do by timing+ -- 1cIII. send `evts`+ Nothing -> (evts'' ++ map mkEvent resetevts, later')+ -- 1b. only `evts` contain a CC to be reset+ -- 1bI. set scheduletime for reset __after__ the latest CC that needs to be reset in `evts`+ -- 1bII. add `resets` to `evts`+ -- 1bIII. send `evts` + Just (_, latestO, _) -> (before +++ map (+ \(t, o, e) ->+ let midionset = scheduleTime (midistart s, rstart s) latestO+ in (midionset, t,o,makeRawEvent e midionset)+ ) resetevts ++ after, later')+ where+ (before, after) = partition (\(m,_,o,_) -> m > scheduleTime (midistart s, rstart s) o) evts''++ -- 1a. `later` contains a cc to be reset, (omit searching in evts)+ -- 1aI. set scheduletime for reset __after__ the latest CC that needs to be reset in `later`+ -- 1aII. add `resetevts` to `later`+ -- 1aIII. send `evts` + Just (latestT, _, _) -> (evts'', later' ++ map (\(_, _, e) -> (latestT, e)) resetevts)+ evtstosend' = map (\(_,_,_,e) -> e) evtstosend+ -- filter events that are too late+ late = map (toDescriptor midiTime now) $ filter (\(_,_,t,_) -> t < realToFrac (utcTimeToPOSIXSeconds now)) evtstosend+ -- drop late CC events to avoid glitches+-- evtstosend'' = map (\(_,_,e,_,_) -> e) $ filter (not.isCC) late+ -- write events for this tick to stream+ err <- PM.writeEvents output evtstosend'++ case err of+ PM.NoError -> return (late, laterevts) -- return events for logging in outer scope+ e -> do+ putStrLn ("sending failed: " ++ show e)+ return (late, laterevts)++isCC :: SentEvent -> Bool+isCC (_,_,e,_,_) = (0x0f .&. cc) == 0xB0+ where+ cc = PM.status $ PM.decodeMsg $ PM.message $ e+++ +-- | Buffer a single tick's MIDI events for a single channel of a single connection +store :: Output -> Int -> Tempo -> Tick -> Onset -> Offset -> MidiMap -> ParamMap -> IO ()+store s ch change tick on off ctrls note = storemidi s ch' note' (change, tick, on, offset) ctrls+ where+ (note', nudge) = computeTiming' change on off note+ ch' = fromIntegral ch+ cshape' = cshape s+ offset = Sound.Tidal.MIDI.Control.latency cshape' + nudge++{- |+Returns a function to be called on every tick,+splits the given @ParamMap@ into MIDI note information+and CCs.+-}+mkStore :: Int -> Output -> IO ToMessageFunc+mkStore channel s = return $ \ shape change tick (on,off,m) -> do+ let ctrls = cutShape shape m+ props = cutShape midiShape m+ ctrls' = stripDefaults ctrls+ ctrls'' = toMidiMap (cshape s) <$> ctrls'+ store' = store s channel change tick on off <$> ctrls''+ -- store even non-midi params, otherwise removing last ctrl results in a missing reset since diff in `flushBackend` would be empty+ -- then buffer ctrl messages to be sent+ -- with the appropriate note properties+ ($) <$> (storeParams s channel <$> stripDefaults (applyShape' shape m)) <*> (($) <$> store' <*> props)+++-- | Union the currently stored paramstate for certain channel with the given one+storeParams :: Output -> Int -> ParamMap -> IO () -> IO ()+storeParams o ch m action = do+ modifyMVar_ (buffer o) $ \(states, events) -> do+ let (before,current:after) = splitAt (ch - 1) states+ state' = Map.union m current+ states' = before ++ [state'] ++ after+ return (states', events)+ action++-- | Thin wrapper around @computeTiming@ to convert onset/offset into onset/duration relative+computeTiming' :: Tempo -> Double -> Double -> ParamMap -> (TimedNote, Double)+computeTiming' tempo on off note = ((fromIntegral n, fromIntegral v, d), nudge)+ where+ ((n,v,d), nudge) = computeTiming tempo (realToFrac (off - on) / S.ticksPerCycle) note++{- | Schedule sending all CC's default values.+Produces an `onTick` handler.+-}+connected :: Int -> String -> Output -> IO ToMessageFunc+connected channel displayname s = do+ let cshape' = cshape s+ shape = toShape $ cshape s+ defaultParams = S.defaultMap shape+ allctrls = toMidiMap cshape' defaultParams+ putStrLn ("Successfully initialized Device '" ++ displayname ++ "'")+ changeState goOnline s+ now <- getCurrentTime+ _ <- storeevents s $ makectrls s (fromIntegral channel) (Tempo now 0 1 False 0,0,0,0) allctrls+ mkStore channel s++-- State handling++readState :: (OutputState -> b) -> Output -> IO b+readState f o = do+ s <- readMVar $ bufferstate o++ return $ f s++isCycling :: OutputState -> Bool+isCycling (0, _, _, True) = True+isCycling _ = False++-- displayState :: OutputState -> String+-- displayState (ticked, conns, paramstate, online) = show ticked ++ "/" ++ show conns ++ "[" ++ show online ++ "]" ++ " active params: " ++ show paramstate++changeState :: (OutputState -> OutputState) -> Output -> IO ()+changeState f o = do+ _ <- changeState' f o+ return ()++changeState' :: (OutputState -> OutputState) -> Output -> IO (OutputState, OutputState)+changeState' f o = do+ bs <- takeMVar stateM+ let fs = f bs+ putMVar stateM fs+ return (fs, bs)+ where+ stateM = bufferstate o++-- | Params in use get overwritten by new ones, except if new ones means _no params_, in this case keep old+resetParamStates :: [ParamMap] -> OutputState -> OutputState+resetParamStates newstates (ticked, conns, paramstates, online) = (ticked, conns, zipWith resetParamState newstates paramstates, online)++resetParamState :: ParamMap -> ParamMap -> ParamMap+resetParamState newstate currentstate+ | Map.empty == newstate = currentstate -- updating with an empty state is a noop+ | otherwise = newstate++goOnline :: OutputState -> OutputState+goOnline (ticked, conns, paramstate, _) = (ticked, conns, paramstate, True)++addConnection :: OutputState -> OutputState+addConnection (ticked, conns, paramstate, online) = (ticked, conns + 1, paramstate, online)++tickConnections :: OutputState -> OutputState+tickConnections (ticked, conns, paramstate, online) = ((ticked + 1) `mod` conns, conns, paramstate, online)++-- | open named MIDI output or use cached (PortMIDI doesn't like opening two connections to the same device!)+useOutput :: MVar MidiDeviceMap -> String -> ControllerShape -> IO (Maybe Output)+useOutput outsM displayname controllershape = do+ outs <- readMVar outsM -- blocks+ let outM = Map.lookup displayname outs -- maybe+ -- if we have a valid output by now, return+ case outM of+ Just o -> do+ putStrLn "Cached Device Output"+ changeState addConnection o -- blocks+ return $ Just o+ Nothing -> do+ -- otherwise open a new output and store the result in the mvar+ devidM <- (>>= maybe (failed displayname "Failed opening MIDI Output Device ID") return) (getIDForDeviceName displayname)+ econn <- outputDevice devidM 1 controllershape -- either+ case econn of+ Left o -> do+ changeState addConnection o+ _ <- swapMVar outsM $ Map.insert displayname o outs+ return $ Just o+ Right _ -> return Nothing+++-- | Turn logicalOnset into MIDITime+scheduleTime :: (CULong, UTCTime)-> Double -> CULong+scheduleTime (mstart', rstart') logicalOnset = (+) mstart $ floor $ 1000 * (logicalOnset - rstart'')+ where+ rstart'' = realToFrac $ utcTimeToPOSIXSeconds rstart'+ mstart = fromIntegral mstart'+ +-- Converters++{-|+Convert a @Param@'s @Value@ into a MIDI consumable datum.++Applies range mapping and scaling functions according to @ControllerShape@+-}+toMidiValue :: ControllerShape -> S.Param -> Value -> Maybe Int+toMidiValue s p (VF x) = ($) <$> mscale <*> mrange <*> pure x+ where+ mrange = fmap range mcc+ mscale = fmap scalef mcc+ mcc = paramN s p+toMidiValue _ _ (VI x) = Just x+toMidiValue _ _ (VS _) = Nothing -- ignore strings for now, we might 'read' them later++-- | Translates generic params into midi params+toMidiMap :: ControllerShape -> S.ParamMap -> MidiMap+toMidiMap s m = Map.mapWithKey (toMidiValue s) m++-- | Keep only params that are in a given shape, replace missing with defaults+cutShape :: S.Shape -> ParamMap -> Maybe ParamMap+cutShape s m = flip Map.intersection (S.defaultMap s) <$> S.applyShape' s m++-- | Keep only params that are in a given shape+stripShape :: S.Shape -> ParamMap -> ParamMap+stripShape s = Map.intersection p'+ where+ p' = S.defaultMap s++-- | Keep only params that are explicitly set (i.e. not default)+stripDefaults :: Maybe ParamMap -> Maybe ParamMap+stripDefaults m = Map.filterWithKey (\k v -> v /= defaultValue k) <$> m+++-- Event creation++-- FIXME: throws if param cannot be found+makectrls :: Output -> MIDIChannel -> MIDITime -> MidiMap -> [MIDIEvent]+makectrls o ch t ctrls = concatMap (\(param', ctrl) -> makeCtrl ch (fromJust $ paramN shape param') (fromIntegral ctrl) t) ctrls'+ where+ shape = cshape o+ ctrls' = filter ((>=0) . snd) $ Map.toList $ Map.mapMaybe id ctrls++makenote :: MIDIChannel -> TimedNote -> MIDITime -> [MIDIEvent]+makenote ch (note,vel,dur) (tempo,tick,onset,offset) = noteon' ++ noteoff'+ where+ noteon' = noteOn ch midinote vel (tempo,tick,onset,offset)+ noteoff' = noteOff ch midinote (tempo,tick,onset,offset + fromRational dur)+ midinote = note + 60++makemidi :: Output -> MIDIChannel -> TimedNote -> MIDITime -> MidiMap -> [MIDIEvent]+makemidi o ch (128,_,_) t ctrls = makectrls o ch t ctrls -- HACK: to send only CC use (n + 60) == 128+makemidi o ch note t ctrls = makectrls o ch t ctrls ++ makenote ch note t++-- Event buffering+storemidi :: Output -> MIDIChannel -> TimedNote -> MIDITime -> MidiMap -> IO ()+storemidi o ch n t ctrls = do+ _ <- storeevents o $ makemidi o ch n t ctrls+ return ()+++makeEvent :: MIDIStatus -> MIDINote -> MIDIChannel -> MIDIVelocity -> MIDITime -> MIDIEvent+makeEvent st n ch v t = (t, msg)+ where+ msg = (ch, st, n, v)++storeevents :: Output -> [MIDIEvent] -> IO (Maybe a)+storeevents o evts = do+ let buf = buffer o+ (paramstate, cbuf) <- takeMVar buf+ putMVar buf (paramstate, cbuf ++ evts)+ return Nothing++-- Misc helpers++showLate :: SentEvent -> String+showLate (o, t, e, m, n) =+ unwords ["late",+ show $ (\x -> [PM.status x, PM.data1 x, PM.data2 x]) $ PM.decodeMsg $ PM.message e,+ "midi now ", show m, " midi onset: ", show o,+ "onset (relative): ", show $ showFFloat (Just 3) (t - realToFrac (utcTimeToPOSIXSeconds n)) "",+ ", sched: ", show $ PM.timestamp e]++showEvent :: PM.PMEvent -> String+showEvent e = show t ++ " " ++ show msg+ where msg = PM.decodeMsg $ PM.message e+ t = PM.timestamp e++showRawEvent :: (CULong, MIDITime, Double, PM.PMEvent) -> String+showRawEvent (_, (_,_,onset,offset), logicalOnset, e) = "(" ++ show onset ++ "," ++ show offset ++ ") / " ++ show logicalOnset ++ " " ++ showEvent e++failed :: (Show a, Show b) => a -> b -> c+failed di err = error (show err ++ ": " ++ show di)+++---------------+-- LOW LEVEL --+---------------++-- MIDI Event wrapping+makeRawEvent :: MIDIMessage -> CULong -> PM.PMEvent+makeRawEvent (ch, st, n, v) = PM.PMEvent msg+ where msg = PM.encodeMsg $ PM.PMMsg (encodeChannel ch st) n v+++-- MIDI Utils+encodeChannel :: MIDIChannel -> MIDIStatus -> CLong+encodeChannel ch cc = (-) ch 1 .|. cc+++-- MIDI Messages+noteOn :: MIDIChannel -> MIDINote -> MIDIVelocity -> MIDITime -> [MIDIEvent]+noteOn ch val vel t = [makeEvent 0x90 val ch vel t]++noteOff :: MIDIChannel -> MIDINote -> MIDITime -> [MIDIEvent]+noteOff ch val t = [makeEvent 0x80 val ch 60 t]++makeCtrl :: MIDIChannel -> ControlChange -> MIDIDatum -> MIDITime -> [MIDIEvent]+makeCtrl ch CC {midi=midi'} n t = makeCC ch (fromIntegral midi') n t -- FIXME: no SysEx support right now+makeCtrl ch NRPN {midi=midi'} n t = makeNRPN ch (fromIntegral midi') n t++makeCC :: MIDIChannel -> MIDIDatum -> MIDIDatum -> MIDITime -> [MIDIEvent]+makeCC ch c n t = [makeEvent 0xB0 c ch n t]++makeNRPN :: MIDIChannel -> MIDIDatum -> MIDIDatum -> MIDITime -> [MIDIEvent]+makeNRPN ch c n t = [+ nrpn 0x63 ch (shift (c .&. 0x3F80) (-7)) t,+ nrpn 0x62 ch (c .&. 0x7F) t,+ nrpn 0x06 ch (shift (n .&. 0x3F80) (-7)) t,+ nrpn 0x26 ch (n .&. 0x7F) t+ ]+ where+ nrpn = makeEvent 0xB0+++-- | Creates an 'Output' wrapping a PortMidi device+outputDevice :: PM.DeviceID -> Int -> ControllerShape -> IO (Either Output PM.PMError)+outputDevice deviceID latency' shape = do+ _ <- PM.initialize+ result <- PM.openOutput deviceID latency'+ bs <- newMVar (0, 0, replicate 16 Map.empty, False)+ case result of+ Left dev ->+ do+ info <- PM.getDeviceInfo deviceID+ time <- getCurrentTime + mstart <- PM.time + putStrLn ("Opened: " ++ show (PM.interface info) ++ ": " ++ show (PM.name info))+ b <- newMVar (replicate 16 Map.empty, [])++ return (Left Output { cshape=shape, conn=dev, buffer=b, bufferstate=bs, midistart=mstart, rstart=time })+ Right err -> return (Right err)
Sound/Tidal/MIDI/Stream.hs view
@@ -1,368 +1,91 @@-module Sound.Tidal.MIDI.Stream (midiStream, midiBackend, midiState, midiSetters, midiDevices,send) where+{-|+Entry functions for interacting with MIDI devices through Tidal.+-}+module Sound.Tidal.MIDI.Stream (midiStream, midiBackend, midiState, midiSetters, midiDevices, displayOutputDevices) where -import Control.Monad.Trans.Maybe -- generics+import Control.Concurrent+import Control.Concurrent.MVar () import qualified Data.Map as Map-import Data.List (sortBy)-import Data.Maybe-import Data.Ord (comparing)-import Data.Time (getCurrentTime, UTCTime, diffUTCTime)-import Data.Time.Clock.POSIX-import Control.Concurrent-import Control.Concurrent.MVar-import Data.Bits-import Foreign.C-import Control.Applicative -import Numeric- -- Tidal specific-import Sound.Tidal.Tempo (Tempo, cps, clockedTick)-import Sound.Tidal.Stream as S-import Sound.Tidal.Utils-import Sound.Tidal.Time-import Sound.Tidal.Transition (transition)+import Sound.Tidal.Stream as S+import Sound.Tidal.Time+import Sound.Tidal.Transition (transition) -- MIDI specific-import Sound.Tidal.MIDI.Device-import Sound.Tidal.MIDI.Control-import qualified Sound.PortMidi as PM+import Sound.Tidal.MIDI.Control+import Sound.Tidal.MIDI.Output -type ConnectionCount = Int-type TickedConnectionCount = Int-type OutputOnline = Bool-type OutputState = (TickedConnectionCount, ConnectionCount, OutputOnline)-type MIDITime = (Tempo, Int, Double, Double)-type MIDIEncoder = CULong -> PM.PMEvent-type MIDIEvent = (MIDITime, MIDIEncoder)+{-|+Create a handle for all currently used 'Output's indexed by their device name. -data Output = Output {- conn :: PM.PMStream,- buffer :: MVar [MIDIEvent],- bufferstate :: MVar OutputState- }+We use this to cache once opened devices. -type MidiMap = Map.Map S.Param (Maybe Int)-type MidiDeviceMap = Map.Map String Output+This will be passed to _every_ initialization of a virtual stream to a MIDI device+and is necessary since, 'PortMidi' only allows a single connection to a device.+-}+midiDevices :: IO (MVar MidiDeviceMap)+midiDevices = newMVar $ Map.fromList [] -toMidiEvent :: ControllerShape -> S.Param -> Value -> Maybe Int-toMidiEvent s p (VF x) = ($) <$> mscale <*> mrange <*> pure x- where- mrange = fmap range mcc- mscale = fmap scalef mcc- mcc = paramN s p-toMidiEvent s p (VI x) = Just x-toMidiEvent s p (VS x) = Nothing -- ignore strings for now, we might 'read' them later--toMidiMap :: ControllerShape -> S.ParamMap -> MidiMap-toMidiMap s m = Map.mapWithKey (toMidiEvent s) (Map.mapMaybe (id) m)--send s ch cshape shape change tick o ctrls (tdur:tnote:trest) = midi- where- midi = sendmidi s cshape ch' (note, vel, dur) (change, tick, o, offset) ctrls- note = fromIntegral $ ivalue $ snd tnote- dur = realToFrac $ fvalue $ snd tdur- (vel, nudge) = case length trest of- 2 -> (mkMidi $ trest !! 1, fvalue $ snd $ trest !! 0)- 1 -> (mkMidi $ trest !! 0, 0)- ch' = fromIntegral ch- mkMidi = fromIntegral . floor . (*127) . fvalue . snd- offset = ((Sound.Tidal.MIDI.Control.latency cshape) + nudge)--mkSend cshape channel s = return $ (\ shape change tick (o,m) -> do- let defaulted = (S.applyShape' shape m)- -- split ParamMap into Properties and Controls- mpartition = fmap (Map.partitionWithKey (\k _ -> (name k) `elem` ["dur", "n", "velocity", "nudge"])) defaulted- props = fmap fst mpartition- ctrls = fmap snd mpartition- props' = fmap (Map.toAscList) $ fmap (Map.mapMaybe (id)) props- -- only send explicitly set Control values- ctrls' = fmap (Map.filterWithKey (\k v -> v /= (defaultValue k))) ctrls- ctrls'' = fmap (toMidiMap cshape) ctrls'- send' = fmap (send s channel cshape shape change tick o) ctrls''- ($) <$> send' <*> props'- )--connected cshape channel name s = do- putStrLn ("Successfully initialized Device '" ++ name ++ "'")- changeState goOnline s- mkSend cshape channel s--failed di err = do- error (show err ++ ": " ++ show di)--notfound name = do- putStrLn "List of Available Device Names"- putStrLn =<< displayOutputDevices- error ("Device '" ++ show name ++ "' not found")--readState f o = do- s <- readMVar $ bufferstate o- let fs = f s- (ticked, conns, online) = s- return fs--isCycling (0, conns, True) = True-isCycling _ = False--displayState (ticked, conns, online) = show ticked ++ "/" ++ show conns ++ "[" ++ show online ++ "]"--changeState f o = do- bs <- takeMVar stateM- let fs = f bs- (ticked, conns, online) = fs - putMVar stateM $ fs- where- stateM = bufferstate o+{-|+Connect to a MIDI device with a given name and channel,+using a 'ControllerShape' to allow customized interaction+with specific MIDI synths. -goOnline (ticked, conns, online) = (ticked, conns, True)-addConnection (ticked, conns, online) = (ticked, conns + 1, online)-tickConnections (ticked, conns, online) = ((ticked + 1) `mod` conns, conns, online)+Needs a 'MidiDeviceMap' to operate, create on using 'midiDevices'! -useOutput outsM name lat = do- outs <- readMVar outsM -- blocks- let outM = Map.lookup name outs -- maybe- -- if we have a valid output by now, return- case outM of- Just o -> do- putStrLn "Cached Device Output"- changeState addConnection o -- blocks- return $ Just o- Nothing -> do- -- otherwise open a new output and store the result in the mvar- devidM <- (>>= maybe (failed name "Failed opening MIDI Output Device ID") return) (getIDForDeviceName name)- econn <- outputDevice devidM lat -- either- case econn of- Left o -> do- changeState addConnection o- swapMVar outsM $ Map.insert name o outs- return $ Just o- Right _ -> return Nothing+Usage: -makeConnection :: MVar (MidiDeviceMap) -> String -> Int -> ControllerShape -> IO ((S.ToMessageFunc), Output)-makeConnection devicesM deviceName channel cshape = do- moutput <- useOutput devicesM deviceName 1- case moutput of- Just o -> do- s <- connected cshape channel deviceName o- return (s, o)- Nothing ->- --failed o- error "Failed"+@+(m1, mt1) <- midiSetters devices "My Synth Controller Device name" 1 synthController getNow+@ -showLate :: (CULong, Double, PM.PMEvent, CULong, UTCTime) -> String-showLate (o, t, e, m, n) =- unwords ["late",- (show $ (\x -> [PM.status x, PM.data1 x, PM.data2 x]) $ PM.decodeMsg $ PM.message e),- "midi now ", show m, " midi onset: ", show o,- "onset (relative): ", show $ showFFloat (Just 3) (t - (realToFrac $ utcTimeToPOSIXSeconds n)) "",- ", sched: ", show $ PM.timestamp e]+To find the correct name for your device see 'displayOutputDevices'+-}+midiSetters :: MVar MidiDeviceMap -- ^ A list of MIDI output devices+ -> String -- ^ The name of the output device to connect+ -> Int -- ^ The MIDI Channel to use+ -> ControllerShape -- ^ The definition of params to be usable+ -> IO Time -- ^ a method to get the current time+ -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())+midiSetters d n c s getNow = do+ ds <- midiState d n c s+ return (setter ds, transition getNow ds) --- should only send out events if all connections have ticked-flushBackend :: Output -> S.Shape -> Tempo -> Int -> IO ()-flushBackend o shape change ticks = do- changeState tickConnections o- cycling <- readState isCycling o-- case cycling of- True -> do- late <- sendevents o shape change ticks- let len = length late- - case len of- 0 ->- return ()- _ -> do- putStrLn $ showLate $ head late- putStrLn $ "and " ++ show (len - 1) ++ " more"- False -> do- s <- readState displayState o- - return ()- --midiDevices :: IO (MVar (MidiDeviceMap))-midiDevices = do- newMVar $ Map.fromList []--midiBackend d n c cs = do- (s, o) <- makeConnection d n c cs- return $ Backend s (flushBackend o)+{-|+Creates a single virtual stream to a MIDI device using a specific 'ControllerShape' +Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'!+-}+midiStream :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (ParamPattern -> IO ()) midiStream d n c s = do backend <- midiBackend d n c s stream backend (toShape s) +{-|+Creates a single virtual state for a MIDI device using a specific 'ControllerShape'++This state can be used to either create a 'Sound.Tidal.Stream.setter' or a 'Sound.Tidal.Transition.transition' from it.++Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'!+-}+midiState :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (MVar (ParamPattern, [ParamPattern])) midiState d n c s = do backend <- midiBackend d n c s S.state backend (toShape s) -midiSetters :: MVar (MidiDeviceMap) -> String -> Int -> ControllerShape -> IO Time -> IO (ParamPattern -> IO (), (Time -> [ParamPattern] -> ParamPattern) -> ParamPattern -> IO ())-midiSetters d n c s getNow = do- ds <- midiState d n c s- return (setter ds, transition getNow ds) --toDescriptor midiTime now (o,m,t,e) = (o,t,e, midiTime, now)--calcOnsets (a@(tempo, tick, onset, offset), e) = (a, logicalOnset' tempo tick onset offset, e)--showEvent :: PM.PMEvent -> String-showEvent e = show t ++ " " ++ show msg - where msg = PM.decodeMsg $ PM.message e- t = PM.timestamp e--showRawEvent :: (CULong, MIDITime, Double, PM.PMEvent) -> String-showRawEvent (midionset, (tempo,tick,onset,offset), logicalOnset, e) = show onset ++ " " ++ " / " ++ show logicalOnset ++ " " ++ showEvent e--sendevents :: Output -> S.Shape -> Tempo -> Int -> IO ([(CULong, Double, PM.PMEvent, CULong, UTCTime)])-sendevents stream shape change ticks = do- let buf = buffer stream- output = conn stream- buf' <- tryTakeMVar buf- case buf' of- Nothing -> do- return []- Just [] -> do- -- make sure we put back an empty buffer- putMVar buf []- return []- (Just evts@(x:xs)) -> do- midiTime <- PM.time- now <- getCurrentTime- - let offset = S.latency shape- nextTick = logicalOnset' change (ticks+1) 0 offset- onsets = map calcOnsets evts- -- split into events sent now and later (e.g. a noteOff that would otherwise cut off noteOn's in the next tick)- (evts', later) = span ((< nextTick).(\(_,o,_) -> o)) $ sortBy (comparing (\(_,o,_) -> o)) onsets- -- calculate MIDI time to schedule events, putting time into fn to create PM.PMEvents- evts'' = map (\(t, o, e) -> let midionset = scheduleTime midiTime now o- in (midionset, t, o, e midionset)) evts'- later' = map (\(t,o,e) -> (t,e)) later- evts''' = map (\(_,_,_,e) -> e) evts''- -- filter events that are too late- late = map (toDescriptor midiTime now) $ filter (\(_,_,t,_) -> t < (realToFrac $ utcTimeToPOSIXSeconds now)) $ evts''-- -- write events for this tick to stream- err <- PM.writeEvents output evts'''- -- store later events for nextTick- putMVar buf later'- case err of- PM.NoError -> do- -- return events for logging in outer scope- return late- e -> do- putStrLn "sending failed"- return []---sendctrls :: Output -> ControllerShape -> CLong -> MIDITime -> MidiMap -> IO ()-sendctrls stream shape ch t ctrls = do- let ctrls' = filter ((>=0) . snd) $ Map.toList $ Map.mapMaybe (id) ctrls- sequence_ $ map (\(param, ctrl) -> makeCtrl stream ch (fromJust $ paramN shape param) (fromIntegral ctrl) t) ctrls' -- FIXME: we should be sure param has ControlChange- return ()--sendnote :: Output -> t -> CLong -> (CLong, CLong, Double) -> MIDITime -> IO ()-sendnote stream shape ch (note,vel, dur) (tempo,tick,onset,offset) =- do- noteOn stream ch midinote vel (tempo,tick,onset,offset)- noteOff stream ch midinote (tempo, tick, onset, offset + dur)- return ()- where midinote = note + 60--scheduleTime :: CULong -> UTCTime -> Double -> CULong-scheduleTime mnow' now' logicalOnset = t- where- now = realToFrac $ utcTimeToPOSIXSeconds $ now'- mnow = fromIntegral mnow'- t = floor $ mnow + (1000 * (logicalOnset - now)) -- 1 second are 1000 microseconds as is the unit of timestamps in PortMidi- --sendmidi :: Output -> ControllerShape -> CLong -> (CLong, CLong, Double) -> MIDITime -> MidiMap -> IO ()-sendmidi stream shape ch n t ctrls = do- sendmidi' stream shape ch n t ctrls- return ()---sendmidi' stream shape ch (128,vel,dur) t ctrls = do- sendctrls stream shape ch t ctrls- return ()-sendmidi' stream shape ch (note,vel,dur) t ctrls = do- sendnote stream shape ch (note,vel,dur) t- sendctrls stream shape ch t ctrls- return ()----- MIDI Utils-encodeChannel :: (Bits a, Num a) => a -> a -> a-encodeChannel ch cc = (((-) ch 1) .|. cc)----- MIDI Messages-noteOn :: Output -> CLong -> CLong -> CLong -> MIDITime -> IO (Maybe a)-noteOn o ch val vel t = do- let evt = (t, \t' -> makeEvent 0x90 val ch vel t')- sendEvent o evt--noteOff :: Output -> CLong -> CLong -> MIDITime -> IO (Maybe a)-noteOff o ch val t = do- let evt = (t, \t' -> makeEvent 0x80 val ch 60 t')- sendEvent o evt--makeCtrl :: Output -> CLong -> ControlChange -> CLong -> MIDITime -> IO (Maybe a)-makeCtrl o ch (CC {midi=midi, range=range}) n t = makeCC o ch (fromIntegral midi) n t-makeCtrl o ch (NRPN {midi=midi, range=range}) n t = makeNRPN o ch (fromIntegral midi) n t---- This is sending CC-makeCC :: Output -> CLong -> CLong -> CLong -> MIDITime -> IO (Maybe a)-makeCC o ch c n t = do- let evt = (t, \t' -> makeEvent 0xB0 c ch n t')- sendEvent o evt---- This is sending NRPN-makeNRPN :: Output -> CLong -> CLong -> CLong -> MIDITime -> IO (Maybe a)-makeNRPN o ch c n t = do- let nrpn = makeEvent 0xB0- evts = [(t, (\t' -> nrpn 0x63 ch (shift (c .&. 0x3F80) (-7)) t')),- (t, (\t' -> nrpn 0x62 ch (c .&. 0x7F) t')),- (t, (\t' -> nrpn 0x06 ch (shift (n .&. 0x3F80) (-7)) t')),- (t, (\t' -> nrpn 0x26 ch (n .&. 0x7F) t'))- ]- mapM (sendEvent o) evts- return Nothing----- Port Midi Wrapper--outputDevice :: PM.DeviceID -> Int -> IO (Either Output PM.PMError)-outputDevice deviceID latency = do- PM.initialize- now <- getCurrentTime- result <- PM.openOutput deviceID latency- bs <- newMVar (0, 0, False)- case result of- Left dev ->- do- info <- PM.getDeviceInfo deviceID- putStrLn ("Opened: " ++ show (PM.interface info) ++ ": " ++ show (PM.name info))- buffer <- newMVar []-- return (Left Output { conn=dev, buffer=buffer, bufferstate=bs })- Right err -> return (Right err)---makeEvent :: CLong -> CLong -> CLong -> CLong -> CULong -> PM.PMEvent-makeEvent st n ch v t = PM.PMEvent msg (t)- where msg = PM.encodeMsg $ PM.PMMsg (encodeChannel ch st) (n) (v)+{-|+Opens a connection to a MIDI device and wraps it in a 'Sound.Tidal.Stream.Backend' implementation. -sendEvent :: Output -> (MIDITime, (CULong -> PM.PMEvent)) -> IO (Maybe a)-sendEvent o evt = do- let buf = buffer o+Needs a 'MidiDeviceMap' to operate, create one using 'midiDevices'!+-}+midiBackend :: MVar MidiDeviceMap -> String -> Int -> ControllerShape -> IO (Backend a)+midiBackend d n c cs = do+ (s, o) <- makeConnection d n c cs+ return $ Backend s (flushBackend o) - cbuf <- takeMVar buf- putMVar buf (cbuf ++ [evt])- return Nothing
Sound/Tidal/MIDI/Synth.hs view
@@ -1,17 +1,18 @@ module Sound.Tidal.MIDI.Synth where -import Sound.Tidal.Params import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params synthController :: ControllerShape-synthController = ControllerShape {- controls = [- mCC modwheel_p 1,- mCC pan_p 10,- mCC expression_p 11,- mCC sustainpedal_p 64- ],- latency = 0.04+synthController =+ ControllerShape+ { controls =+ [ mCC modwheel_p 1+ , mCC pan_p 10+ , mCC expression_p 11+ , mCC sustainpedal_p 64+ ]+ , latency = 0.1 } synth = toShape synthController
− Sound/Tidal/MIDI/SynthParams.hs
@@ -1,46 +0,0 @@-{- |-Module: SynthParams-Description: Parameters to control synth--In general, synth parameters specify patterns of sounds, and patterns of effects on those sounds. These are the synthesis parameters you can use with the default Dirt synth:--}-module Sound.Tidal.MIDI.SynthParams (- sound,- grp,- accelerate,- bandf,- bandq,- begin,- channel,- coarse,- crush,- cut,- cutoff,- cutoffegint,- delay,- delayfeedback,- delaytime,- detune,- dry,- end,- gain,- hcutoff,- hresonance,- loop,- n,- nudge,- offset,- orbit,- pan,- resonance,- room,- shape,- size,- speed,- s,- unit,- velocity,- vowel - ) where--import Sound.Tidal.Params
+ Sound/Tidal/MIDI/Synthino.hs view
@@ -0,0 +1,55 @@+module Sound.Tidal.MIDI.Synthino where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++synthinoController :: ControllerShape+synthinoController =+ ControllerShape+ { controls =+ [ mCC attack_p 73+ , mCC decay_p 75+ , mCC sustain_p 79+ , mCC release_p 72+ , mCC waveform_p 70+ , mCC pitchlforate_p 76+ , mCC pitchlfodepth_p 1+ , mCC lfowaveform_p 12+ , mCC filterlforate_p 13+ , mCC filterlfodepth_p 91+ , mCC peak_p 71+ , mCC cutoff_p 74+ , mCC bpm_p 16+ , mCC arplength_p 17+ , mCC arptranspose_p 18+ , mCC vol_p 7+ , mCC off_p 123+ ]+ , latency = 0.1+ }++synthino = toShape synthinoController++(waveform, waveform_p) = pF "waveform" (Just 0)++(pitchlforate, pitchlforate_p) = pF "pitchlforate" (Just 0)++(pitchlfodepth, pitchlfodepth_p) = pF "pitchlfodepth" (Just 0)++(lfowaveform, lfowaveform_p) = pF "lfowaveform" (Just 0)++(filterlforate, filterlforate_p) = pF "filterlforate" (Just 0)++(filterlfodepth, filterlfodepth_p) = pF "filterlfodepth" (Just 0)++(peak, peak_p) = pF "peak" (Just 0)++(bpm, bpm_p) = pF "bpm" (Just 0)++(arplength, arplength_p) = pF "arplength" (Just 0)++(arptranspose, arptranspose_p) = pF "arptranspose" (Just 0)++(vol, vol_p) = pF "vol" (Just 0)++(off, off_p) = pF "off" (Just 0)
Sound/Tidal/MIDI/System1M.hs view
@@ -1,118 +1,170 @@ module Sound.Tidal.MIDI.System1M where -import Sound.Tidal.Params import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params system1mController :: ControllerShape-system1mController = ControllerShape {controls = [- mCC rmod_p 1,- mCC rlpcutoff_p 3,- mCC rport_p 5,- mCC rres_p 9,- mCC rcrush_p 12,- mCC rdelaytime_p 13,- mCC rosc1_p 16,- mCC rosc2_p 17,- mCC rsub_p 18,- mCC rnoise_p 19,- mCC rpitchenv_p 22,- mCC rpitchatk_p 23,- mCC rpitchdecay_p 24,- mCC rlfopitch_p 26,- mCC rlfofade_p 27,- mCC rlfofilter_p 28,- mCC rlforate_p 29,- mCC rlfoamp_p 30,- mCC rlfotype_p 35,- mCC rosc1type_p 46,- mCC rosc1range_p 47,- mCC rosc1color_p 50,- mCC rosc1xmod_p 52,- mCC rosc2color_p 55,- mCC rosc2tune_p 56,- mCC rosc1mod_p 60,- mCC rosc2type_p 61,- mCC rosc2range_p 62,- mCC rosc2mod_p 63,- mCC ramptone_p 69,- mCC rhpcutoff_p 79,- mCC rfilterenv_p 81,- mCC rfilterkey_p 82,- mCC rfilteratk_p 83,- mCC rfilterdecay_p 84,- mCC rfiltersustain_p 85,- mCC rfilterrelease_p 86,- mCC rampatk_p 89,- mCC rampdecay_p 90,- mCC rreverb_p 91,- mCC rdelay_p 94,- mCC rampsustain_p 96,- mCC ramprelease_p 97,- mCC rosc2ring_p 111,- mCC rosc2sync_p 112,- mCC rsubtype_p 113,- mCC rnoisetype_p 114,- mCC rlpftype_p 115,- mCC rlegato_p 116,- mCC rlfokeytrig_p 117,- mCC rtemposync_p 118,- mCC rmono_p 119- ],- -- duration = ("dur", 0.05),- -- velocity = ("vel", 0.5),- latency = 0.1}+system1mController =+ ControllerShape+ { controls =+ [ mCC rmod_p 1+ , mCC rlpcutoff_p 3+ , mCC rport_p 5+ , mCC rres_p 9+ , mCC rcrush_p 12+ , mCC rdelaytime_p 13+ , mCC rosc1_p 16+ , mCC rosc2_p 17+ , mCC rsub_p 18+ , mCC rnoise_p 19+ , mCC rpitchenv_p 22+ , mCC rpitchatk_p 23+ , mCC rpitchdecay_p 24+ , mCC rlfopitch_p 26+ , mCC rlfofade_p 27+ , mCC rlfofilter_p 28+ , mCC rlforate_p 29+ , mCC rlfoamp_p 30+ , mCC rlfotype_p 35+ , mCC rosc1type_p 46+ , mCC rosc1range_p 47+ , mCC rosc1color_p 50+ , mCC rosc1xmod_p 52+ , mCC rosc2color_p 55+ , mCC rosc2tune_p 56+ , mCC rosc1mod_p 60+ , mCC rosc2type_p 61+ , mCC rosc2range_p 62+ , mCC rosc2mod_p 63+ , mCC ramptone_p 69+ , mCC rhpcutoff_p 79+ , mCC rfilterenv_p 81+ , mCC rfilterkey_p 82+ , mCC rfilteratk_p 83+ , mCC rfilterdecay_p 84+ , mCC rfiltersustain_p 85+ , mCC rfilterrelease_p 86+ , mCC rampatk_p 89+ , mCC rampdecay_p 90+ , mCC rreverb_p 91+ , mCC rdelay_p 94+ , mCC rampsustain_p 96+ , mCC ramprelease_p 97+ , mCC rosc2ring_p 111+ , mCC rosc2sync_p 112+ , mCC rsubtype_p 113+ , mCC rnoisetype_p 114+ , mCC rlpftype_p 115+ , mCC rlegato_p 116+ , mCC rlfokeytrig_p 117+ , mCC rtemposync_p 118+ , mCC rmono_p 119+ ]+ , latency = 0.1+ } -oscKeys = toShape system1mController+system1m = toShape system1mController (rmod, rmod_p) = pF "rmod" (Just 0)+ (rlpcutoff, rlpcutoff_p) = pF "rlpcutoff" (Just 0)+ (rport, rport_p) = pF "rport" (Just 0)+ (rres, rres_p) = pF "rres" (Just 0)+ (rcrush, rcrush_p) = pF "rcrush" (Just 0)+ (rdelaytime, rdelaytime_p) = pF "rdelaytime" (Just 0)+ (rosc1, rosc1_p) = pF "rosc1" (Just 0)+ (rosc2, rosc2_p) = pF "rosc2" (Just 0)+ (rsub, rsub_p) = pF "rsub" (Just 0)+ (rnoise, rnoise_p) = pF "rnoise" (Just 0)+ (rpitchenv, rpitchenv_p) = pF "rpitchenv" (Just 0)+ (rpitchatk, rpitchatk_p) = pF "rpitchatk" (Just 0)+ (rpitchdecay, rpitchdecay_p) = pF "rpitchdecay" (Just 0)+ (rlfopitch, rlfopitch_p) = pF "rlfopitch" (Just 0)+ (rlfofade, rlfofade_p) = pF "rlfofade" (Just 0)+ (rlfofilter, rlfofilter_p) = pF "rlfofilter" (Just 0)+ (rlforate, rlforate_p) = pF "rlforate" (Just 0)+ (rlfoamp, rlfoamp_p) = pF "rlfoamp" (Just 0)+ (rlfotype, rlfotype_p) = pF "rlfotype" (Just 0)+ (rosc1type, rosc1type_p) = pF "rosc1type" (Just 0)+ (rosc1range, rosc1range_p) = pF "rosc1range" (Just 0)+ (rosc1color, rosc1color_p) = pF "rosc1color" (Just 0)+ (rosc1xmod, rosc1xmod_p) = pF "rosc1xmod" (Just 0)+ (rosc2color, rosc2color_p) = pF "rosc2color" (Just 0)+ (rosc2tune, rosc2tune_p) = pF "rosc2tune" (Just 0)+ (rosc1mod, rosc1mod_p) = pF "rosc1mod" (Just 0)+ (rosc2type, rosc2type_p) = pF "rosc2type" (Just 0)+ (rosc2range, rosc2range_p) = pF "rosc2range" (Just 0)+ (rosc2mod, rosc2mod_p) = pF "rosc2mod" (Just 0)+ (ramptone, ramptone_p) = pF "ramptone" (Just 0)+ (rhpcutoff, rhpcutoff_p) = pF "rhpcutoff" (Just 0)+ (rfilterenv, rfilterenv_p) = pF "rfilterenv" (Just 0)+ (rfilterkey, rfilterkey_p) = pF "rfilterkey" (Just 0)+ (rfilteratk, rfilteratk_p) = pF "rfilteratk" (Just 0)+ (rfilterdecay, rfilterdecay_p) = pF "rfilterdecay" (Just 0)+ (rfiltersustain, rfiltersustain_p) = pF "rfiltersustain" (Just 0)+ (rfilterrelease, rfilterrelease_p) = pF "rfilterrelease" (Just 0)+ (rampatk, rampatk_p) = pF "rampatk" (Just 0)+ (rampdecay, rampdecay_p) = pF "rampdecay" (Just 0)+ (rreverb, rreverb_p) = pF "rreverb" (Just 0)+ (rdelay, rdelay_p) = pF "rdelay" (Just 0)+ (rampsustain, rampsustain_p) = pF "rampsustain" (Just 0)+ (ramprelease, ramprelease_p) = pF "ramprelease" (Just 0)+ (rosc2ring, rosc2ring_p) = pF "rosc2ring" (Just 0)+ (rosc2sync, rosc2sync_p) = pF "rosc2sync" (Just 0)+ (rsubtype, rsubtype_p) = pF "rsubtype" (Just 0)+ (rnoisetype, rnoisetype_p) = pF "rnoisetype" (Just 0)+ (rlpftype, rlpftype_p) = pF "rlpftype" (Just 0)+ (rlegato, rlegato_p) = pF "rlegato" (Just 0)+ (rlfokeytrig, rlfokeytrig_p) = pF "rlfokeytrig" (Just 0)+ (rtemposync, rtemposync_p) = pF "rtemposync" (Just 0)+ (rmono, rmono_p) = pF "rmono" (Just 0)
+ Sound/Tidal/MIDI/Tetra.hs view
@@ -0,0 +1,694 @@+{-# LANGUAGE OverloadedStrings #-}+{-|+Mapping and Abstractions for the analog four-voice synthesizer, TETR4 by Dave Smith Instruments.++Rather than being a tutorial on how to write your own mappings for your MIDI devices, this is more like the kitchen sink: it shows what is possible.++The DSI TETR4 has four separate voices that can (when set to multi-mode) be controlled via four different MIDI channels. Almost everything you can control directly on the device can be automated via MIDI messages.+-}+module Sound.Tidal.MIDI.Tetra where++import Sound.Tidal.MIDI.Control++import Sound.Tidal.Params+ hiding (cutoff_p, attack_p, decay_p, sustain_p, release_p)+import Sound.Tidal.Pattern (Pattern(..), atom)+import Sound.Tidal.Stream+ ((|+|), (|=|), ( # ), merge, ParamPattern)++import Control.Applicative++{-|+The controller mapping for TETR4++To get the most out of this device with tidal, I chose to use the non-registered parameter (NRPN) variant to control it. This allows to use the full spectrum for controls like @cutoff@ that allow more granular stepping than standard MIDI (164 instead of 128 steps).++Many parameters diverge from the default ranges of 0 to 127 and therefore this mapping uses the @mapRange@ functionality for controls to allow you to always use double params, e.g.:++>>> t1 $ n (run 4) # famt "0.5" # cutoff "0.3" # resonance "0.8"++while @famt@, @cutoff@ and @resonance@ all have different ranges of operation (0..254, 0..14 and 0..127 respectively)++Some parameters are essentially mode switches and I chose to pass the values you enter into patterns directly through to the resulting control change. The method @passThru@ on control specification simply skips the scaling of values (you can write your own scaler if you want).++For very generic control I reused Tidal's own params, like @cutoff@, @attack@, @gain@, @pan@ and @release@. Sometimes the defaults for Tidal do not make sense for MIDI. See @(_, cutoff_p)@ below the actual controller shape for examples on how to deal with this.+-}+tetraController :: ControllerShape+tetraController =+ ControllerShape+ { controls =+ [ mrNRPN osc1freq_p 0 (0, 120)+ , mrNRPN osc1detune_p 1 (0, 100)+ , NRPN osc1shape_p 2 (0, 103) passThru+ , mNRPN osc1glide_p 3+ , NRPN osc1kbd_p 4 (0, 1) passThru+ , mrNRPN osc2freq_p 5 (0, 120)+ , mrNRPN osc2detune_p 6 (0, 100)+ , NRPN osc2shape_p 7 (0, 103) passThru+ , mNRPN osc2glide_p 8+ , NRPN osc2kbd_p 9 (0, 1) passThru+ , NRPN oscsync_p 10 (0, 1) passThru+ , NRPN glidemode_p 11 (0, 3) passThru+ , NRPN oscslop_p 12 (0, 5) passThru+ , mrNRPN oscmix_p 13 (0, 127)+ , mNRPN noise_p 14+ , mrNRPN cutoff_p 15 (0, 164)+ , mNRPN resonance_p 16+ , mNRPN kamt_p 17+ , mNRPN audiomod_p 18+ , NRPN fpoles_p 19 (0, 1) passThru+ -- filter envelope+ , mrNRPN famt_p 20 (0, 254)+ , mNRPN fvel_p 21+ , mNRPN fdel_p 22+ , mNRPN fatk_p 23+ , mNRPN fdcy_p 24+ , mNRPN fsus_p 25+ , mNRPN frel_p 26+ , mNRPN vcavol_p 27+ , mNRPN pan_p 28+ , mNRPN gain_p 29 -- max volume by default+ , mrNRPN vamt_p 30 (0, 127) -- max vca envelope amount+ , mNRPN vvel_p 31+ , mNRPN vdel_p 32+ , mNRPN attack_p 33+ , mrNRPN decay_p 34 (0, 127)+ , mrNRPN sustain_p 35 (0, 127)+ , mNRPN release_p 36+ , NRPN lfo1rate_p 37 (0, 166) passThru+ , NRPN lfo1shape_p 38 (0, 4) passThru+ , mNRPN lfo1amt_p 39+ , NRPN lfo1dest_p 40 (0, 43) passThru+ , NRPN lfo1sync_p 41 (0, 1) passThru+ , NRPN lfo2rate_p 42 (0, 166) passThru -- unsynced+ , NRPN lfo2shape_p 43 (0, 4) passThru+ , mNRPN lfo2amt_p 44+ , NRPN lfo2dest_p 45 (0, 43) passThru+ , NRPN lfo2sync_p 46 (0, 1) passThru+ , NRPN lfo3rate_p 47 (0, 166) passThru -- unsynced+ , NRPN lfo3shape_p 48 (0, 4) passThru+ , mNRPN lfo3amt_p 49+ , NRPN lfo3dest_p 50 (0, 43) passThru+ , NRPN lfo3sync_p 51 (0, 1) passThru+ , NRPN lfo4rate_p 52 (0, 166) passThru -- unsynced+ , NRPN lfo4shape_p 53 (0, 4) passThru+ , mNRPN lfo4amt_p 54+ , NRPN lfo4dest_p 55 (0, 43) passThru+ , NRPN lfo4sync_p 56 (0, 1) passThru+ , NRPN emod_p 57 (0, 43) passThru+ , mrNRPN eamt_p 58 (0, 254)+ , mNRPN evel_p 59+ , mNRPN edel_p 60+ , mNRPN eatk_p 61+ , mNRPN edcy_p 62+ , mNRPN esus_p 63+ , mNRPN erel_p 64+ , NRPN mod1src_p 65 (0, 20) passThru+ , mrNRPN mod1amt_p 66 (0, 254)+ , NRPN mod1dst_p 67 (0, 47) passThru+ , NRPN mod2src_p 68 (0, 20) passThru+ , mrNRPN mod2amt_p 69 (0, 254)+ , NRPN mod2dst_p 70 (0, 47) passThru+ , NRPN mod3src_p 71 (0, 20) passThru+ , mrNRPN mod3amt_p 72 (0, 254)+ , NRPN mod3dst_p 73 (0, 47) passThru+ , NRPN mod4src_p 74 (0, 20) passThru+ , mrNRPN mod4amt_p 75 (0, 254)+ , NRPN mod4dst_p 76 (0, 47) passThru+ , NRPN seq1dst_p 77 (0, 47) passThru+ , NRPN seq2dst_p 78 (0, 47) passThru+ , NRPN seq3dst_p 79 (0, 47) passThru+ , NRPN seq4dst_p 80 (0, 47) passThru+ , mrNRPN mwhl_p 81 (0, 254)+ , NRPN mwhldst_p 82 (0, 47) passThru+ , mrNRPN aftt_p 83 (0, 254)+ , NRPN afttdst_p 84 (0, 47) passThru+ , mrNRPN breath_p 85 (0, 254)+ , NRPN breathdst_p 86 (0, 47) passThru+ , mrNRPN mvel_p 87 (0, 254)+ , NRPN mveldst_p 88 (0, 47) passThru+ , mrNRPN foot_p 89 (0, 254)+ , NRPN footdst_p 90 (0, 47) passThru+ , NRPN kbpm_p 91 (30, 250) passThru+ , NRPN clockdiv_p 92 (0, 12) passThru -- TODO: document values+ , NRPN bendrng_p 93 (0, 12) passThru+ , NRPN sqntrig_p 94 (0, 4) passThru -- TODO: document values+ , NRPN unisonkey_p 95 (0, 5) passThru -- TODO: document values+ , NRPN unisonmode_p 96 (0, 4) passThru -- TODO: document values+ , NRPN arpmode_p 97 (0, 14) passThru+ , NRPN erepeat_p 98 (0, 1) passThru+ , NRPN unison_p 99 (0, 1) passThru+ , NRPN arp_p 100 (0, 1) passThru+ , NRPN sqn_p 101 (0, 1) passThru+ , NRPN mcr1_p 105 (0, 183) passThru+ , NRPN mcr2_p 106 (0, 183) passThru+ , NRPN mcr3_p 107 (0, 183) passThru+ , NRPN mcr4_p 108 (0, 183) passThru+ , mNRPN shape_p 110+ , mrNRPN btnfreq_p 111 (0, 127)+ , mrNRPN btnvel_p 112 (0, 127)+ , NRPN btnmode_p 113 (0, 1) passThru+ , mNRPN pitch1_p 114+ , mNRPN pitch2_p 115+ , mNRPN fbvol_p 116+ -- left out: editor byte,+ , mrNRPN ksplitpoint_p 118 (0, 127)+ -- each patch has layer a/b+ , NRPN kmode_p 119 (0, 2) passThru -- 0: normal, 1: stack, both layers respond to full key range, 2: split at ksplitpoint+ , mCC notesoff_p 123+ , mCC ccreset_p 121+ , mCC damp_p 64+ ]+ , latency = 0.1+ }++tetra = toShape tetraController++(notesoff, notesoff_p) = pF "notesoff" (Just 0)++(ccreset, ccreset_p) = pF "ccreset" (Just 0)++(damp, damp_p) = pF "damp" (Just (-1))++(osc1freq, osc1freq_p) = pF "osc1freq" (Just 0.2)++(osc1detune, osc1detune_p) = pF "osc1detune" (Just 0.5)++(osc1shape, osc1shape_p) = pI "osc1shape" (Just 1)++(osc1glide, osc1glide_p) = pF "osc1glide" (Just 0)++(osc1kbd, osc1kbd_p) = pI "osc1kbd" (Just 1)++(osc2freq, osc2freq_p) = pF "osc2freq" (Just 0.2)++(osc2detune, osc2detune_p) = pF "osc2detune" (Just 0.5)++(osc2shape, osc2shape_p) = pI "osc2shape" (Just 1)++(osc2glide, osc2glide_p) = pF "osc2glide" (Just 0)++(osc2kbd, osc2kbd_p) = pI "osc2kbd" (Just 1)++(oscsync, oscsync_p) = pF "oscsync" (Just 0)++(glidemode, glidemode_p) = pI "glidemode" (Just 0)++(oscslop, oscslop_p) = pF "oscslop" (Just 0)++(oscmix, oscmix_p) = pF "oscmix" (Just 0.5)++(noise, noise_p) = pF "noise" (Just 0)++(kamt, kamt_p) = pF "kamt" (Just 0.5)++-- overridden defaults for MIDI+(_, cutoff_p) = pF "cutoff" (Just 1)++(_, attack_p) = pF "attack" (Just 0.12)++(_, release_p) = pF "release" (Just 0.01)++(_, decay_p) = pF "decay" (Just 0.5)++(_, sustain_p) = pF "sustain" (Just 0.5)++(audiomod, audiomod_p) = pF "audiomod" (Just 0)++(fpoles, fpoles_p) = pI "fpoles" (Just 0)++twopole = fpoles "0"++fourpole = fpoles "1"++-- filter envelope+(famt, famt_p) = pF "famt" (Just 0.5)++(fvel, fvel_p) = pF "fvel" (Just 0)++(fdel, fdel_p) = pF "fdel" (Just 0)++(fatk, fatk_p) = pF "fatk" (Just 0.01)++(fdcy, fdcy_p) = pF "fdcy" (Just 0)++(fsus, fsus_p) = pF "fsus" (Just 0)++(frel, frel_p) = pF "frel" (Just 0.01)++(vcavol, vcavol_p) = pF "vcavol" (Just 0)++(vamt, vamt_p) = pF "vamt" (Just 1)++(vvel, vvel_p) = pF "vvel" (Just 0)++(vdel, vdel_p) = pF "vdel" (Just 0)++(lfo1rate, lfo1rate_p) = pF "lfo1rate" (Just 0)++(lfo1shape, lfo1shape_p) = pI "lfo1shape" (Just 0)++(lfo1amt, lfo1amt_p) = pF "lfo1amt" (Just 0)++(lfo1dest, lfo1dest_p) = pF "lfo1dest" (Just 0)++(lfo1sync, lfo1sync_p) = pI "lfo1sync" (Just 0)++(lfo2rate, lfo2rate_p) = pF "lfo2rate" (Just 0)++(lfo2shape, lfo2shape_p) = pI "lfo2shape" (Just 0)++(lfo2amt, lfo2amt_p) = pF "lfo2amt" (Just 0)++(lfo2dest, lfo2dest_p) = pF "lfo2dest" (Just 0)++(lfo2sync, lfo2sync_p) = pI "lfo2sync" (Just 0)++(lfo3rate, lfo3rate_p) = pF "lfo3rate" (Just 0)++(lfo3shape, lfo3shape_p) = pI "lfo3shape" (Just 0)++(lfo3amt, lfo3amt_p) = pF "lfo3amt" (Just 0)++(lfo3dest, lfo3dest_p) = pF "lfo3dest" (Just 0)++(lfo3sync, lfo3sync_p) = pI "lfo3sync" (Just 0)++(lfo4rate, lfo4rate_p) = pF "lfo4rate" (Just 0)++(lfo4shape, lfo4shape_p) = pI "lfo4shape" (Just 0)++(lfo4amt, lfo4amt_p) = pF "lfo4amt" (Just 0)++(lfo4dest, lfo4dest_p) = pF "lfo4dest" (Just 0)++(lfo4sync, lfo4sync_p) = pI "lfo4sync" (Just 0)++(emod, emod_p) = pF "emod" (Just 0)++(eamt, eamt_p) = pF "eamt" (Just 0.5)++(evel, evel_p) = pF "evel" (Just 0)++(edel, edel_p) = pF "edel" (Just 0)++(eatk, eatk_p) = pF "eatk" (Just 0.01)++(edcy, edcy_p) = pF "edcy" (Just 0)++(esus, esus_p) = pF "esus" (Just 0)++(erel, erel_p) = pF "erel" (Just 0.01)++(mod1src, mod1src_p) = pF "mod1src" (Just 0)++(mod1amt, mod1amt_p) = pF "mod1amt" (Just 0.5)++(mod1dst, mod1dst_p) = pF "mod1dst" (Just 0)++(mod2src, mod2src_p) = pF "mod2src" (Just 0)++(mod2amt, mod2amt_p) = pF "mod2amt" (Just 0.5)++(mod2dst, mod2dst_p) = pF "mod2dst" (Just 0)++(mod3src, mod3src_p) = pF "mod3src" (Just 0)++(mod3amt, mod3amt_p) = pF "mod3amt" (Just 0.5)++(mod3dst, mod3dst_p) = pF "mod3dst" (Just 0)++(mod4src, mod4src_p) = pF "mod4src" (Just 0)++(mod4amt, mod4amt_p) = pF "mod4amt" (Just 0.5)++(mod4dst, mod4dst_p) = pF "mod4dst" (Just 0)++(seq1dst, seq1dst_p) = pF "seq1dst" (Just 0)++(seq2dst, seq2dst_p) = pF "seq2dst" (Just 0)++(seq3dst, seq3dst_p) = pF "seq3dst" (Just 0)++(seq4dst, seq4dst_p) = pF "seq4dst" (Just 0)++(mwhl, mwhl_p) = pF "mwhl" (Just 0.5)++(mwhldst, mwhldst_p) = pI "mwhldst" (Just 0)++(aftt, aftt_p) = pF "aftt" (Just 0.5)++(afttdst, afttdst_p) = pI "afttdst" (Just 0)++(breath, breath_p) = pF "breath" (Just 0.5)++(breathdst, breathdst_p) = pI "breathdst" (Just 0)++(mvel, mvel_p) = pF "mvel" (Just 0.5)++(mveldst, mveldst_p) = pI "mveldst" (Just 0)++(foot, foot_p) = pF "foot" (Just 0.5)++(footdst, footdst_p) = pI "footdst" (Just 0)++(bendrng, bendrng_p) = pI "bendrng" (Just 0)++-- left out: modwheel, breath, footctrl, pressure, velocity+(kbpm, kbpm_p) = pI "kbpm" (Just 0)++(clockdiv, clockdiv_p) = pI "clockdiv" (Just 0)++-- left out: pitchbend range+(sqntrig, sqntrig_p) = pF "sqntrig" (Just 0)++(unisonkey, unisonkey_p) = pF "unisonkey" (Just 0)++(unisonmode, unisonmode_p) = pF "unisonmode" (Just 0)++(arpmode, arpmode_p) = pF "arpmode" (Just 0)++(erepeat, erepeat_p) = pF "erepeat" (Just 0)++(unison, unison_p) = pF "unison" (Just 0)++(arp, arp_p) = pF "arp" (Just 0)++(sqn, sqn_p) = pF "sqn" (Just 0)++(mcr1, mcr1_p) = pI "mcr1" (Just 0)++(mcr2, mcr2_p) = pI "mcr2" (Just 0)++(mcr3, mcr3_p) = pI "mcr3" (Just 0)++(mcr4, mcr4_p) = pI "mcr4" (Just 0)++(btnfreq, btnfreq_p) = pF "btnfreq" (Just 0.25)++(btnvel, btnvel_p) = pF "btnvel" (Just 1)++(btnmode, btnmode_p) = pF "btnmode" (Just 0)++(sub1vol, sub1vol_p) = pF "sub1vol" (Just 0)++(sub2vol, sub2vol_p) = pF "sub2vol" (Just 0)++(fbvol, fbvol_p) = pF "fbvol" (Just 0)++(ksplitpoint, ksplitpoint_p) = pF "ksplitpoint" (Just 0.5)++(kmode, kmode_p) = pF "kmode" (Just 0)++knormal = kmode "0"++kstack = kmode "0.5"++ksplit = kmode "1"++{-| Abstractions++Though not yet finished, these are some examples on how to combine multiple parameters into one single function you can use within your patterns.++Since Tidal 0.7 you can use the @grp@ method to allow things like:++>>> t1 $ n (run 4) # adsr "0.1:0.6:0.3:0.9 0.8:0.3:0.9:0.1"++which alternates between two filter envelope shapes, the first one with a sharp attack and a long decay/release and the latter with a long attack, high sustain and a short release.++-}+-- adsr+adsr = grp [attack_p, decay_p, sustain_p, release_p]++atk3 = grp [attack_p, fatk_p, eatk_p]++dcy3 = grp [decay_p, fdcy_p, edcy_p]++sus3 = grp [sustain_p, fsus_p, esus_p]++rel3' = grp [release_p, frel_p, erel_p]++-- lfo+lfotri = doublePattern 0++lforsaw = doublePattern 1++lfosaw = doublePattern 2++lfopulse = doublePattern 3++lforand = doublePattern 4++{-|+A hack to handle a param with completely different behavior for certain parts of the range:++@lrate@ is limited from 0 to 150 and specifies values that will produce an lfo frequency++@lstep@ however is essentially limited from 0 to 16 and specifies values that will produce rhythmic lfo based on the _sequence speed_. as taken from the manual:++0: 32 steps+1: 16 steps+2: 8 steps+3: 6 steps+4: 4 steps+5: 3 steps+6: 2 steps+7: 1.5 steps+8: 1 step+9: 2/3 steps+10: 1/2 step+11: 1/3 step+12: 1/4 step+13: 1/6 step+14: 1/8 step+15: 1/16 step++-}+lrate r = min 150 . max 0 <$> r++lstep s = min 166 . max 151 . (+ 150) <$> s++lfo1 s d r a = lfo1shape s |+| lfo1dest d |+| lfo1rate r |+| lfo1amt a++lfo2 s d r a = lfo2shape s |+| lfo2dest d |+| lfo2rate r |+| lfo2amt a++lfo3 s d r a = lfo3shape s |+| lfo3dest d |+| lfo3rate r |+| lfo3amt a++lfo4 s d r a = lfo4shape s |+| lfo4dest d |+| lfo4rate r |+| lfo4amt a++-- mod+mod1 s d a = mod1src s |+| mod1dst d |+| mod1amt a++mod2 s d a = mod2src s |+| mod2dst d |+| mod2amt a++mod3 s d a = mod3src s |+| mod3dst d |+| mod3amt a++mod4 s d a = mod4src s |+| mod4dst d |+| mod4amt a++{-| Modulation++named sources and destinations to able to refer them for lfos, mods and also sequences.+-}+doublePattern d = atom d :: Pattern Double++dosc1 = doublePattern 1++dosc2 = doublePattern 2++dosc = doublePattern 3++dmix = doublePattern 4++dnoise = doublePattern 5++dpw1 = doublePattern 6++dpw2 = doublePattern 7++dpw = doublePattern 8++dcut = doublePattern 9++dres = doublePattern 10++damod = doublePattern 11++dvca = doublePattern 12++dspread = doublePattern 13++dlfo1f = doublePattern 14++dlfo2f = doublePattern 15++dlfo3f = doublePattern 16++dlfo4f = doublePattern 17++dlfof = doublePattern 18++dlfo1a = doublePattern 19++dlfo2a = doublePattern 20++dlfo3a = doublePattern 21++dlfo4a = doublePattern 22++dlfoa = doublePattern 23++dfamt = doublePattern 24++dvamt = doublePattern 25++deamt = doublePattern 26++damt = doublePattern 27++dfatk = doublePattern 28++dvatk = doublePattern 29++deatk = doublePattern 30++datk = doublePattern 31++dfdcy = doublePattern 32++dvdcy = doublePattern 33++dedcy = doublePattern 34++ddcy = doublePattern 35++dfrel = doublePattern 36++dvrel = doublePattern 37++derel = doublePattern 38++drel = doublePattern 39++dmod1 = doublePattern 40++dmod2 = doublePattern 41++dmod3 = doublePattern 42++dmod4 = doublePattern 43++dfb = doublePattern 44++dsub1 = doublePattern 45++dsub2 = doublePattern 46++dshape = doublePattern 47++dslew = doublePattern 48++-- mod sources+sseq1 = doublePattern 1++sseq2 = doublePattern 2++sseq3 = doublePattern 3++sseq4 = doublePattern 4++slfo1 = doublePattern 5++slfo2 = doublePattern 6++slfo3 = doublePattern 7++slfo4 = doublePattern 8++sfenv = doublePattern 9++svenv = doublePattern 10++seenv = doublePattern 11++spitchb = doublePattern 12++smodwh = doublePattern 13++saftert = doublePattern 14++sbreath = doublePattern 15++sfoot = doublePattern 16++sexpr = doublePattern 17++svel = doublePattern 18++snote = doublePattern 19++snoise = doublePattern 20++{-|+Presets suck, but I constantly forget how to make drums+with the TETR4, so here are some defaults (that can mostly be changed when using them)+to make a snare and a kick.++Use the snare like this:++>>> t1 $ n "0(3,8)" # snare++To make it shorter:++>>> t1 $ n "0(3,8)" # snare |-| release "0.1" |-| decay "0.1"+-}+snare =+ fourpole |=| osc1shape "0" |+| osc1kbd "0" |+| osc2shape "0" |+| osc2kbd "0" |+|+ noise "1" |+|+ shape "0.7" |+|+ fbvol "0.3" |=|+ resonance "0.2" |+|+ release "0.3" |+|+ sustain "0" |+|+ decay "0.3" |+|+ cutoff "1" |+|+ dur "0.02"++{-|+usage would be:++>>> t1 $ n "0 [[0 1] 1]" # kick++you can change the defaults by applying merge operations for certain params:++>>> t1 $ n "0(3,8)" # kick |+| edcy "0.05"++will give the kick more resonance++>>> t1 $ n "0(3,8)" # kick |-| edcy "0.15"++will make it really dry+-}+kick =+ fourpole |+| osc1shape "0" |+| osc1kbd "0" |+| osc2shape "0" |+| osc2kbd "0" |+|+ sustain "0" |+|+ decay "0.95" |+|+ release "0.5" |+|+ resonance "0.99" |+|+ cutoff "0.001" |+|+ eamt "0.8" |+|+ emod "9" |+|+ edcy "0.2"++{-|+Since the TETR4 lacks a high-pass filter, things like snares and especially cymbals are somewhat limited to filtered noise which sounds okish.++Therefore some presets for the different types of sounds you can get from the TETR4 can come in handy and can also be combined and modified with and through others:+-}+{-|+A chip tune like sound, reminds me of gameboys+-}+chip =+ osc1shape "2" # osc2shape "2" |+| osc2freq "0.23" # osc1glide "0.05" #+ osc2glide "0.05" #+ glidemode "3" #+ release "0.78"
Sound/Tidal/MIDI/VolcaBass.hs view
@@ -1,27 +1,26 @@ module Sound.Tidal.MIDI.VolcaBass where -import Sound.Tidal.Params import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params -bassController :: ControllerShape-bassController = ControllerShape { controls = [- mCC slide_p 5,- mCC expression_p 11,- mCC octave_p 40,- mCC lfo_p 41,- mCC lfoint_p 42,- mCC pitch1_p 43,- mCC pitch2_p 44,- mCC pitch3_p 45,- mCC attack_p 46,- mCC decay_p 47,- mCC cutoff_p 48,- mCC gate_p 49- ],- --duration = ("dur", 0.05),- --velocity = ("vel", 0.5),- latency = 0.01- }- -bass = toShape bassController+volcabassController :: ControllerShape+volcabassController =+ ControllerShape+ { controls =+ [ mCC slide_p 5+ , mCC expression_p 11+ , mCC octave_p 40+ , mCC lfo_p 41+ , mCC lfoint_p 42+ , mCC pitch1_p 43+ , mCC pitch2_p 44+ , mCC pitch3_p 45+ , mCC attack_p 46+ , mCC decay_p 47+ , mCC cutoff_p 48+ , mCC gate_p 49+ ]+ , latency = 0.1+ } +volcabass = toShape volcabassController
Sound/Tidal/MIDI/VolcaBeats.hs view
@@ -1,35 +1,34 @@ module Sound.Tidal.MIDI.VolcaBeats where -import Sound.Tidal.Params import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params -beatsController :: ControllerShape-beatsController = ControllerShape { controls = [- mCC lkick_p 40,- mCC lsnare_p 41,- mCC llotom_p 42,- mCC lhitom_p 43,- mCC lclhat_p 44,- mCC lophat_p 45,- mCC lclap_p 46,- mCC lclaves_p 47,- mCC lagogo_p 48,- mCC lcrash_p 49,- mCC sclap_p 50,- mCC sclaves_p 51,- mCC sagogo_p 52,- mCC scrash_p 53,- mCC stuttertime_p 54,- mCC stutterdepth_p 55,- mCC tomdecay_p 56,- mCC clhatdecay_p 57,- mCC ophatdecay_p 58,- mCC hatgrain_p 59- ],- -- duration = ("dur", 0.05),- -- velocity = ("vel", 0.5),- latency = 0.01- }+volcabeatsController :: ControllerShape+volcabeatsController =+ ControllerShape+ { controls =+ [ mCC lkick_p 40+ , mCC lsnare_p 41+ , mCC llotom_p 42+ , mCC lhitom_p 43+ , mCC lclhat_p 44+ , mCC lophat_p 45+ , mCC lclap_p 46+ , mCC lclaves_p 47+ , mCC lagogo_p 48+ , mCC lcrash_p 49+ , mCC sclap_p 50+ , mCC sclaves_p 51+ , mCC sagogo_p 52+ , mCC scrash_p 53+ , mCC stuttertime_p 54+ , mCC stutterdepth_p 55+ , mCC tomdecay_p 56+ , mCC clhatdecay_p 57+ , mCC ophatdecay_p 58+ , mCC hatgrain_p 59+ ]+ , latency = 0.1+ } --- What is this used for?-beats = toShape beatsController+volcabeats = toShape volcabeatsController
+ Sound/Tidal/MIDI/VolcaFM.hs view
@@ -0,0 +1,39 @@+module Sound.Tidal.MIDI.VolcaFM where++import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params++volcafmController :: ControllerShape+volcafmController =+ ControllerShape+ { controls =+ [ mCC octave_p 40+ , mCC velocity_p 41+ , mCC modattack_p 42+ , mCC moddecay_p 43+ , mCC carattack_p 44+ , mCC cardecay_p 45+ , mCC lfo_p 46+ , mCC lfopitchint_p 47+ , mCC algtm_p 48+ , mCC arp_p 49+ , mCC arpdiv_p 50+ ]+ , latency = 0.1+ }++(modattack, modattack_p) = pF "modattack" (Just 0)++(moddecay, moddecay_p) = pF "moddecay" (Just 0)++(carattack, carattack_p) = pF "carattack" (Just 0)++(cardecay, cardecay_p) = pF "cardecay" (Just 0)++(algtm, algtm_p) = pF "algtm" (Just 0)++(arp, arp_p) = pF "arp" (Just 0)++(arpdiv, arpdiv_p) = pF "arpdiv" (Just 0)++volcafm = toShape volcafmController
Sound/Tidal/MIDI/VolcaKeys.hs view
@@ -1,30 +1,30 @@ module Sound.Tidal.MIDI.VolcaKeys where -import Sound.Tidal.Params import Sound.Tidal.MIDI.Control+import Sound.Tidal.Params -keysController :: ControllerShape-keysController = ControllerShape { controls = [- mCC portamento_p 5,- mCC expression_p 11,- mCC voice_p 40, -- voi- mCC octave_p 41, -- oct- mCC detune_p 42, -- det- mCC vcoegint_p 43, -- vco- mCC cutoff_p 44, -- ctf- mCC vcfegint_p 45, -- vcf- mCC lfo_p 46,- mCC lfopitchint_p 47, -- lfop- mCC lfocutoffint_p 48, -- lfoc- mCC attack_p 49, -- att- mCC decay_p 50, -- dec- mCC sustain_p 51, -- sus- mCC delaytime_p 52, -- delayt- mCC delayfeedback_p 53 -- delayfb- ],- -- duration = ("dur", 0.05),- -- velocity = ("vel", 0.5),- latency = 0.01- }+volcakeysController :: ControllerShape+volcakeysController =+ ControllerShape+ { controls =+ [ mCC portamento_p 5+ , mCC expression_p 11+ , mCC voice_p 40 -- voi+ , mCC octave_p 41 -- oct+ , mCC detune_p 42 -- det+ , mCC vcoegint_p 43 -- vco+ , mCC cutoff_p 44 -- ctf+ , mCC vcfegint_p 45 -- vcf+ , mCC lfo_p 46+ , mCC lfopitchint_p 47 -- lfop+ , mCC lfocutoffint_p 48 -- lfoc+ , mCC attack_p 49 -- att+ , mCC decay_p 50 -- dec+ , mCC sustain_p 51 -- sus+ , mCC delaytime_p 52 -- delayt+ , mCC delayfeedback_p 53 -- delayfb+ ]+ , latency = 0.1+ } -keys = toShape keysController+volcakeys = toShape volcakeysController
tidal-midi.cabal view
@@ -1,5 +1,5 @@ name: tidal-midi-version: 0.8.2+version: 0.9 synopsis: MIDI support for tidal -- description: homepage: http://tidal.lurk.org/@@ -19,18 +19,27 @@ library Exposed-modules: Sound.Tidal.MIDI.Context- Sound.Tidal.MIDI.Device Sound.Tidal.MIDI.Control+ Sound.Tidal.MIDI.Device+ Sound.Tidal.MIDI.Stream+ Sound.Tidal.MIDI.Output+ Sound.Tidal.MIDI.CC+ Sound.Tidal.MIDI.GMPerc+ Sound.Tidal.MIDI.Synth+ Sound.Tidal.MIDI.Synthino+ Sound.Tidal.MIDI.Blofeld+ Sound.Tidal.MIDI.MBase01+ Sound.Tidal.MIDI.Tetra+ Sound.Tidal.MIDI.Ambika+ Sound.Tidal.MIDI.MiniAtmegatron Sound.Tidal.MIDI.VolcaBeats Sound.Tidal.MIDI.VolcaBass Sound.Tidal.MIDI.VolcaKeys- Sound.Tidal.MIDI.Stream- Sound.Tidal.MIDI.Synth- Sound.Tidal.MIDI.SynthParams+ Sound.Tidal.MIDI.VolcaFM Sound.Tidal.MIDI.System1M Sound.Tidal.MIDI.KorgKP3 - Build-depends: base < 5, tidal == 0.8.2, PortMidi == 0.1.6.0, time, containers, transformers+ Build-depends: base < 5, tidal == 0.9, PortMidi == 0.1.6.0, time, containers, transformers source-repository head type: git