{-# OPTIONS_GHC -threaded #-}
module DobutokO.Sound.Octaves (
  
  octaveUp
  , octaveDown
  , liftInOctave
  , liftInOctaveV
) where
import Data.Maybe (fromJust)
import qualified Data.Vector as V
import DobutokO.Sound.Functional.Basics
octaveUp :: Float -> Float
octaveUp x = 2 * x
{-# INLINE octaveUp #-}
octaveDown :: Float -> Float
octaveDown x = x / 2
{-# INLINE octaveDown #-}
liftInOctave :: Int -> Float -> Maybe Float
liftInOctave n x
  | compare n 0 == LT || compare n 8 == GT = Nothing
  | compare (closestNote x) 24.4996 == GT =
      case compare (fromJust . whichOctave $ x) n of
        EQ -> Just (closestNote x)
        LT -> let z  = logBase 2.0 (V.unsafeIndex notes (n * 12) / closestNote x)
                  z1 = truncate z in
                   if abs (z - fromIntegral z1) > 0.999 || abs (z - fromIntegral z1) < 0.001
                     then Just (V.unsafeLast . V.iterateN (fromIntegral z1 + 1) octaveUp $ closestNote x)
                     else Just (V.unsafeLast . V.iterateN (fromIntegral z1 + 2) octaveUp $ closestNote x)
        _  -> let z  = logBase 2.0 (closestNote x / V.unsafeIndex notes (n * 12))
                  z1 = truncate z in
                   if abs (z - fromIntegral z1) > 0.999 || abs (z - fromIntegral z1) < 0.001
                     then Just (V.unsafeLast . V.iterateN (fromIntegral z1 + 2) octaveDown $ closestNote x)
                     else Just (V.unsafeLast . V.iterateN (fromIntegral z1 + 1) octaveDown $ closestNote x)
  | otherwise = Nothing
liftInOctaveV :: Int -> V.Vector Float -> V.Vector Float
liftInOctaveV n = V.mapMaybe (liftInOctave n)