{-# LANGUAGE NoImplicitPrelude #-}
{- |
Functions for converting MIDI controller and key values
to something meaningful for signal processing.
-}
module Synthesizer.MIDI.Value where

import qualified Sound.MIDI.Message.Channel.Voice as VoiceMsg

import qualified Algebra.Transcendental as Trans
import qualified Algebra.Field          as Field

import NumericPrelude.Numeric
-- import NumericPrelude.Base


{-# INLINE controllerLinear #-}
controllerLinear ::
   (Field.C y) =>
   (y,y) -> Int -> y
controllerLinear :: forall y. C y => (y, y) -> Int -> y
controllerLinear (y
lower,y
upper) Int
n =
   let k :: y
k = forall a b. (C a, C b) => a -> b
fromIntegral Int
n forall a. C a => a -> a -> a
/ y
127
   in  (y
1forall a. C a => a -> a -> a
-y
k) forall a. C a => a -> a -> a
* y
lower forall a. C a => a -> a -> a
+ y
k forall a. C a => a -> a -> a
* y
upper

{-# INLINE controllerExponential #-}
controllerExponential ::
   (Trans.C y) =>
   (y,y) -> Int -> y
controllerExponential :: forall y. C y => (y, y) -> Int -> y
controllerExponential (y
lower,y
upper) Int
n =
   let k :: y
k = forall a b. (C a, C b) => a -> b
fromIntegral Int
n forall a. C a => a -> a -> a
/ y
127
   in  y
lowerforall a. C a => a -> a -> a
**(y
1forall a. C a => a -> a -> a
-y
k) forall a. C a => a -> a -> a
* y
upperforall a. C a => a -> a -> a
**y
k

{-# INLINE pitchBend #-}
pitchBend ::
   (Trans.C y) =>
   y -> y -> Int -> y
pitchBend :: forall y. C y => y -> y -> Int -> y
pitchBend y
range y
center Int
n =
   y
center forall a. C a => a -> a -> a
* y
range forall a. C a => a -> a -> a
** (forall a b. (C a, C b) => a -> b
fromIntegral Int
n forall a. C a => a -> a -> a
/ y
8192)

{-# INLINE velocity #-}
velocity ::
   (Field.C y) =>
   VoiceMsg.Velocity -> y
velocity :: forall y. C y => Velocity -> y
velocity Velocity
vel =
   forall a b. (C a, C b) => a -> b
fromIntegral (Velocity -> Int
VoiceMsg.fromVelocity Velocity
vel forall a. C a => a -> a -> a
- Int
64)forall a. C a => a -> a -> a
/y
63

{- |
Convert pitch to frequency according to the default tuning
in MIDI 1.0 Detailed Specification.
-}
{-# INLINE frequencyFromPitch #-}
frequencyFromPitch ::
   (Trans.C y) =>
   VoiceMsg.Pitch -> y
frequencyFromPitch :: forall y. C y => Pitch -> y
frequencyFromPitch Pitch
pitch =
   y
440 forall a. C a => a -> a -> a
* y
2 forall a. C a => a -> a -> a
^? (forall a b. (C a, C b) => a -> b
fromIntegral (Pitch -> Int
VoiceMsg.fromPitch Pitch
pitch forall a. C a => a -> a -> a
+ Int
3 forall a. C a => a -> a -> a
- Int
6forall a. C a => a -> a -> a
*Int
12) forall a. C a => a -> a -> a
/ y
12)