{-# LANGUAGE NoImplicitPrelude #-}
{- |
Functions for converting MIDI controller and key values
to something meaningful for signal processing.
-}
module Synthesizer.MIDI.Dimensional.ValuePlain (
   controllerLinear,
   controllerExponential,
   pitchBend,
   frequencyFromPitch,
   ) where

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

import qualified Algebra.DimensionTerm as Dim
import qualified Number.DimensionTerm as DN

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

import NumericPrelude.Numeric
import NumericPrelude.Base


{-# INLINE controllerLinear #-}
controllerLinear ::
   (Field.C y, Dim.C v) =>
   (DN.T v y, DN.T v y) -> Int -> DN.T v y
controllerLinear :: forall y v. (C y, C v) => (T v y, T v y) -> Int -> T v y
controllerLinear (T v y
lower,T v 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  forall u a. (C u, C a) => a -> T u a -> T u a
DN.scale (y
1forall a. C a => a -> a -> a
-y
k) T v y
lower forall a. C a => a -> a -> a
+ forall u a. (C u, C a) => a -> T u a -> T u a
DN.scale y
k T v y
upper

{-# INLINE controllerExponential #-}
controllerExponential ::
   (Trans.C y, Dim.C v) =>
   (DN.T v y, DN.T v y) -> Int -> DN.T v y
controllerExponential :: forall y v. (C y, C v) => (T v y, T v y) -> Int -> T v y
controllerExponential (T v y
lower,T v 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  case forall a. HasCallStack => [Char] -> a
error [Char]
"MIDIValue.controllerExponential dimension" of
          v
d ->
             forall u a. C u => u -> a -> T u a
DN.fromNumberWithDimension v
d forall a b. (a -> b) -> a -> b
$
             forall u a. C u => u -> T u a -> a
DN.toNumberWithDimension v
d T v y
lower forall a. C a => a -> a -> a
** (y
1forall a. C a => a -> a -> a
-y
k) forall a. C a => a -> a -> a
*
             forall u a. C u => u -> T u a -> a
DN.toNumberWithDimension v
d T v y
upper forall a. C a => a -> a -> a
** y
k

{-# INLINE pitchBend #-}
pitchBend ::
   (Trans.C y, Dim.C v) =>
   y -> DN.T v y -> Int -> DN.T v y
pitchBend :: forall y v. (C y, C v) => y -> T v y -> Int -> T v y
pitchBend y
range T v y
center Int
n =
   forall u a. (C u, C a) => a -> T u a -> T u a
DN.scale (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)) T v y
center

{- |
Convert pitch to frequency according to the default tuning
in MIDI 1.0 Detailed Specification.
-}
{-# INLINE frequencyFromPitch #-}
frequencyFromPitch ::
   (Trans.C y) =>
   VoiceMsg.Pitch -> DN.Frequency y
frequencyFromPitch :: forall y. C y => Pitch -> Frequency y
frequencyFromPitch Pitch
pitch =
   forall u a. (C u, C a) => a -> T u a -> T u a
DN.scale
      (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))
      (forall a. a -> Frequency a
DN.frequency y
440)