module Csound.Air.Wav(
readSnd, loopSnd, loopSndBy,
readWav, loopWav, readSegWav,
tempoLoopWav, tempoReadWav,
readSnd1, loopSnd1, loopSndBy1,
readWav1, loopWav1, readSegWav1,
tempoLoopWav1, tempoReadWav1,
LoopMode(..), ramSnd, ramSnd1,
SampleFormat(..),
writeSigs, writeWav, writeAiff, writeWav1, writeAiff1,
lengthSnd, segments,
takeSnd, delaySnd, afterSnd, lineSnd, loopLineSnd, segmentSnd, repeatSnd, toMono
) where
import Data.List(isSuffixOf)
import Csound.Typed
import Csound.Typed.Opcode
import Csound.Tab(mp3s, wavs)
import Csound.Control.Instr(withDur, sched)
import Csound.SigSpace(mapSig)
import Csound.Types(Sig2)
import Csound.Control.Evt(metroE, eventList)
import Csound.Air.Spec
takeSnd :: Sigs a => D -> a -> a
takeSnd dt asig = trigs (const $ return asig) $ eventList [(0, dt, unit)]
delaySnd :: Sigs a => D -> a -> a
delaySnd dt asig = trigs (const $ return asig) $ eventList [(dt, infiniteDur, unit)]
segmentSnd ::Sigs a => D -> D -> a -> a
segmentSnd del dur asig = trigs (const $ return asig) $ eventList [(del, dur, unit)]
repeatSnd :: Sigs a => D -> a -> a
repeatSnd dt asig = sched (const $ return asig) $ segments dt
afterSnd :: (Num b, Sigs b) => D -> b -> b -> b
afterSnd dt a b = takeSnd dt a + delaySnd dt b
lineSnd :: (Num a, Sigs a) => D -> [a] -> a
lineSnd dt xs = foldr1 go xs
where
go a b = afterSnd dt a b
loopLineSnd :: (Num a, Sigs a) => D -> [a] -> a
loopLineSnd dt xs = repeatSnd (dt * (int $ length xs)) $ lineSnd dt xs
isMp3 :: String -> Bool
isMp3 name = ".mp3" `isSuffixOf` name
toMono :: (Sig, Sig) -> Sig
toMono (a, b) = 0.5 * a + 0.5 * b
lengthSnd :: String -> D
lengthSnd fileName
| isMp3 fileName = mp3len $ text fileName
| otherwise = filelen $ text fileName
segments :: D -> Evt (D, Unit)
segments dt = withDur dt $ metroE (sig $ recip dt)
readSnd :: String -> (Sig, Sig)
readSnd fileName
| isMp3 fileName = mp3in (text fileName)
| otherwise = diskin2 (text fileName) 1
loopSndBy :: D -> String -> (Sig, Sig)
loopSndBy dt fileName = repeatSnd dt $ readSnd fileName
loopSnd :: String -> (Sig, Sig)
loopSnd fileName = loopSndBy (lengthSnd fileName) fileName
readWav :: Sig -> String -> (Sig, Sig)
readWav speed fileName = diskin2 (text fileName) speed
loopWav :: Sig -> String -> (Sig, Sig)
loopWav speed fileName = flip withDs [0, 1] $ ar2 $ diskin2 (text fileName) speed
readSegWav :: D -> D -> Sig -> String -> (Sig, Sig)
readSegWav start end speed fileName = takeSnd (end start) $ diskin2 (text fileName) speed `withDs` [start, 1]
tempoReadWav :: Sig -> String -> (Sig, Sig)
tempoReadWav speed fileName = mapSig (scaleSpec (1 / abs speed)) $ diskin2 (text fileName) speed
tempoLoopWav :: Sig -> String -> (Sig, Sig)
tempoLoopWav speed fileName = mapSig (scaleSpec (1 / abs speed)) $ flip withDs [0, 1] $ ar2 $ diskin2 (text fileName) speed
readSnd1 :: String -> Sig
readSnd1 fileName
| isMp3 fileName = toMono $ readSnd fileName
| otherwise = diskin2 (text fileName) 1
loopSndBy1 :: D -> String -> Sig
loopSndBy1 dt fileName = repeatSnd dt $ readSnd1 fileName
loopSnd1 :: String -> Sig
loopSnd1 fileName = loopSndBy1 (lengthSnd fileName) fileName
readWav1 :: Sig -> String -> Sig
readWav1 speed fileName = diskin2 (text fileName) speed
loopWav1 :: Sig -> String -> Sig
loopWav1 speed fileName = flip withDs [0, 1] $ diskin2 (text fileName) speed
readSegWav1 :: D -> D -> Sig -> String -> Sig
readSegWav1 start end speed fileName = takeSnd (end start) $ diskin2 (text fileName) speed `withDs` [start, 1]
tempoReadWav1 :: Sig -> String -> Sig
tempoReadWav1 speed fileName = scaleSpec (1 / abs speed) $ readWav1 speed fileName
tempoLoopWav1 :: Sig -> String -> Sig
tempoLoopWav1 speed fileName = scaleSpec (1 / abs speed) $ loopWav1 speed fileName
data LoopMode = Once | Loop | Bounce
deriving (Show, Eq, Enum)
ramSnd :: LoopMode -> Sig -> String -> Sig2
ramSnd loopMode speed file = loscil3 1 speed t `withDs` [1, int $ fromEnum loopMode]
where t
| isMp3 file = mp3s file 0
| otherwise = wavs file 0 0
ramSnd1 :: LoopMode -> Sig -> String -> Sig
ramSnd1 loopMode speed file
| isMp3 file = (\(aleft, aright) -> 0.5 * (aleft + aright)) $ loscil3 1 speed (mp3s file 0) `withDs` [1, int $ fromEnum loopMode]
| otherwise = loscil3 1 speed (wavs file 0 1) `withDs` [1, int $ fromEnum loopMode]
data SampleFormat
= NoHeaderFloat32
| NoHeaderInt16
| HeaderInt16
| UlawSamples
| Int16
| Int32
| Float32
| Uint8
| Int24
| Float64
deriving (Eq, Ord, Enum)
writeSigs :: FormatType -> SampleFormat -> String -> [Sig] -> SE ()
writeSigs fmt sample file = fout (text file) formatToInt
where
formatToInt = int $ formatTypeToInt fmt * 10 + fromEnum sample
formatTypeToInt :: FormatType -> Int
formatTypeToInt x = case x of
Wav -> 1
Aiff -> 2
Raw -> 3
Ircam -> 4
_ -> error $ "Format " ++ (show x) ++ " is not supported in the writeSnd."
writeWav :: String -> (Sig, Sig) -> SE ()
writeWav file = writeSigs Wav Int16 file . \(a, b) -> [a, b]
writeAiff :: String -> (Sig, Sig) -> SE ()
writeAiff file = writeSigs Aiff Int16 file . \(a, b) -> [a, b]
writeWav1 :: String -> Sig -> SE ()
writeWav1 file = writeWav file . \x -> (x, x)
writeAiff1 :: String -> Sig -> SE ()
writeAiff1 file = writeAiff file . \x -> (x, x)