module Haskore.Interface.Signal.Example.Guitar where

-- the song
import Haskore.Example.Guitar(parallelSong, stringPitches)
-- the instrument
import Filter.Example(guitar)

import qualified Haskore.Basic.Pitch as Pitch
import           Haskore.Music.Standard  as StdMusic
import           Haskore.Music.Rhythmic  as RhyMusic
import qualified Haskore.Performance.Fancy as FancyPf
import qualified Haskore.Interface.Signal.InstrumentMap as InstrMap
import qualified Haskore.Interface.Signal.Write as MusicSignal
import Haskore.Interface.Signal.Write(Time,Volume)

import qualified Synthesizer.Plain.Filter.NonRecursive as FiltNR
import qualified Synthesizer.Plain.Interpolation as Interpolation
import qualified Synthesizer.Plain.Signal as Sig
import           Synthesizer.Plain.Instrument
          (fastBell, simpleSaw, moogGuitar, moogGuitarSoft, fmBell, )
import qualified Sox.File

import           Synthesizer.Utility(mapSnd)

import qualified Data.List as List

import System.Exit(ExitCode)



stringFreqs :: [Time]
stringFreqs =
   map (\p -> Pitch.intToFreq (Pitch.toInt p) / 48000) stringPitches


sampleSong :: RhyMusic.T () Int
sampleSong = parallelSong [0 .. 5]

synthSong :: StdMusic.T
synthSong =
   StdMusic.transpose 12 (parallelSong (repeat "moogguitarsoft"))



----------- Configuration of the player -----------

type IMap instr = InstrMap.InstrumentTable Time Volume instr

guitarToSignal :: Time -> Sig.T Volume -> InstrMap.Instrument Time Volume
guitarToSignal stringFreq sound sampleRate freq =
   Interpolation.multiRelativeZeroPadConstant 0
      (repeat (freq/sampleRate / stringFreq)) sound

sampleMap :: [Sig.T Volume] -> IMap Int
sampleMap samples =
   zipWith3 (\chr stringFreq sound ->
               (chr, guitarToSignal stringFreq sound))
            [0 ..] stringFreqs samples

synthMap :: IMap StdMusic.Instr
synthMap = map (mapSnd (MusicSignal.amplify (1/5::Volume)))
  [("guitar",         (\sampleRate freq -> guitar (freq/sampleRate))),
   ("bell",           fastBell),
   ("string",         simpleSaw),
   ("moogguitar",     moogGuitar),
   ("moogguitarsoft", moogGuitarSoft),
   ("fmguitar",       (\sampleRate -> fmBell sampleRate 0.4 3.003))]

computeSignal :: (Ord drum, Ord instr) =>
   RhyMusic.T drum instr -> IMap instr ->
                    Time -> Sig.T (Volume,Volume)
computeSignal music instrMap sampleRate =
   let channel dif =
          MusicSignal.fromRhythmicMusic sampleRate
             (MusicSignal.detuneInstrs dif instrMap)
             FancyPf.map
             (MusicSignal.contextMetro 60 qn)
             music
   in  zip (channel 1.001) (channel 0.999)

readSamples :: IO [Sig.T Volume]
readSamples =
   do sampledSounds <- mapM Sox.File.readAIFFMono
             (map (\chr -> "guitar/Zupf/Zupf"++chr:".aiff") ['0'..'5'])
      return (zipWith FiltNR.amplifyVector
                      [0.5,0.5,0.5,0.5,0.5,0.3::Volume]
                      sampledSounds)

main :: IO ExitCode
main =
   do
     Sox.File.renderStereo "Guitar" 44100 . computeSignal sampleSong . sampleMap
        =<< readSamples
     Sox.File.renderStereo "GuitarSynth" 44100 (computeSignal synthSong synthMap)