module Reactive.Banana.MIDI.Note where
import qualified Reactive.Banana.MIDI.Pitch as Pitch
import qualified Reactive.Banana.MIDI.Time as Time
import qualified Reactive.Banana.MIDI.Common as Common
import Reactive.Banana.MIDI.Common (PitchChannel(PitchChannel), )
import qualified Sound.MIDI.Message.Class.Query as Query
import qualified Sound.MIDI.Message.Class.Construct as Construct
import qualified Sound.MIDI.Message.Channel.Mode as Mode
import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg
import Sound.MIDI.Message.Channel.Voice (Velocity, Pitch, )
import Control.Monad (mplus, )
import Data.Monoid (mappend, )
data Boundary key value =
Boundary key value Bool
deriving (Eq, Show)
data BoundaryExt key value =
BoundaryExt (Boundary key value)
| AllOff (key -> Bool)
maybeBnd ::
Query.C msg =>
msg -> Maybe (Boundary PitchChannel Velocity)
maybeBnd =
fmap (\(c, (v, p, on)) -> Boundary (PitchChannel p c) v on) . Query.note
maybeBndExt ::
Query.C msg =>
msg -> Maybe (BoundaryExt PitchChannel Velocity)
maybeBndExt ev =
mplus
(fmap BoundaryExt $ maybeBnd ev)
(let allOff chan = Just $ AllOff $ \(PitchChannel _p c) -> chan == c
in case Query.mode ev of
Just (chan, Mode.AllNotesOff) -> allOff chan
Just (chan, Mode.AllSoundOff) -> allOff chan
_ -> Nothing)
class Pitch.C x => Make x where
make :: Construct.C msg => x -> Velocity -> Bool -> msg
instance Make Pitch where
make p =
make (PitchChannel p minBound)
instance Make PitchChannel where
make (PitchChannel p c) vel on =
Construct.note c (vel, p, on)
fromBnd ::
(Make key, Common.VelocityField value, Construct.C msg) =>
Boundary key value -> msg
fromBnd (Boundary pc vel on) =
make pc (Common.getVelocity vel) on
bundle ::
(Construct.C msg) =>
Time.T m Time.Relative Time.Ticks ->
Time.T m Time.Relative Time.Ticks ->
(PitchChannel, Velocity) ->
Common.Bundle m msg
bundle start dur (pc, vel) =
Common.Future start (make pc vel True) :
Common.Future (mappend start dur) (make pc vel False) :
[]
lift ::
(Query.C msg, Construct.C msg) =>
(Boundary PitchChannel Velocity -> Boundary PitchChannel Velocity) ->
(msg -> Maybe msg)
lift f msg =
fmap (fromBnd . f) $ maybeBnd msg
liftMaybe ::
(Query.C msg, Construct.C msg) =>
(Boundary PitchChannel Velocity -> Maybe (Boundary PitchChannel Velocity)) ->
(msg -> Maybe msg)
liftMaybe f msg =
fmap fromBnd . f =<< maybeBnd msg
transpose ::
Int ->
Boundary PitchChannel v ->
Maybe (Boundary PitchChannel v)
transpose d (Boundary (PitchChannel p0 c) v on) =
fmap
(\p1 -> Boundary (PitchChannel p1 c) v on)
(Pitch.increase d p0)
reverse ::
Boundary PitchChannel v ->
Maybe (Boundary PitchChannel v)
reverse (Boundary (PitchChannel p0 c) v on) =
fmap
(\p1 -> Boundary (PitchChannel p1 c) v on)
(Pitch.maybeFromInt $ (60+64 ) $ VoiceMsg.fromPitch p0)
reduceVelocity ::
Velocity ->
Boundary pc Velocity ->
Boundary pc Velocity
reduceVelocity decay (Boundary pc v on) =
Boundary pc
(case VoiceMsg.fromVelocity v of
0 -> v
vel ->
VoiceMsg.toVelocity $
vel min (VoiceMsg.fromVelocity decay) (vel1))
on