module Music.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           Haskore.Performance.Player  as Player
import           Haskore.General.Utility(pairMap)
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 as Syn
import qualified Interpolation
import Instruments
import Sox.File

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 -> [Volume] -> InstrMap.Instrument Time Volume
guitarToSignal stringFreq sound sampleRate freq =
   Interpolation.interpolateConstant 0
      (repeat (freq/sampleRate / stringFreq)) sound

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

synthMap :: IMap StdMusic.Instr
synthMap = map (pairMap (id, 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 -> [(Volume,Volume)]
computeSignal music instrMap sampleRate =
   let channel dif =
          MusicSignal.fromRhyMusic sampleRate
             (MusicSignal.detuneInstrs dif instrMap)
             Player.fancyMap
             (MusicSignal.contextMetro 60 qn)
             music
   in  zip (channel 1.001) (channel 0.999)

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

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