module Sound.SC3.UGen.External.ATS ( ATS(..)
, ATSHeader(..)
, ATSFrame
, atsRead
, atsSC3 ) where
import Control.Monad
import qualified Data.ByteString.Lazy as B
import Data.List
import Sound.OpenSoundControl
import System.IO
data ATS = ATS { atsHeader :: ATSHeader
, atsFrames :: [ATSFrame] }
deriving (Eq, Show)
data ATSHeader = ATSHeader { atsSampleRate :: Double
, atsFrameSize :: Int
, atsWindowSize :: Int
, atsNPartials :: Int
, atsNFrames :: Int
, atsMaxAmplitude :: Double
, atsMaxFrequency :: Double
, atsAnalysisDuration :: Double
, atsFileType :: Int
} deriving (Eq, Show)
type ATSFrame = [Double]
atsRead :: FilePath -> IO ATS
atsRead fn = do
h <- openFile fn ReadMode
v <- B.hGet h 8
let reader = get_reader v
hdr_r <- replicateM 9 (reader h)
let f j = hdr_r !! (j 1)
g = floor . f
ft = g 9
(n, x) = ftype_n ft
np = g 4
nf = g 5
fl = np * n + x
hdr = ATSHeader (f 1) (g 2) (g 3) np nf (f 6) (f 7) (f 8) ft
get_f = replicateM fl (reader h)
d <- replicateM nf get_f
hClose h
return (ATS hdr d)
atsSC3 :: ATS -> [Double]
atsSC3 (ATS h d) =
let f = fromIntegral
td = transpose d
in f (atsFileType h) :
f (atsNPartials h) :
f (atsNFrames h) :
f (atsWindowSize h) :
concatMap (td !!) (atsSC3Indices h)
read_f64 :: Handle -> IO Double
read_f64 h = liftM decode_f64 (B.hGet h 8)
read_f64LE :: Handle -> IO Double
read_f64LE h = liftM (decode_f64 . B.reverse) (B.hGet h 8)
get_reader :: B.ByteString -> (Handle -> IO Double)
get_reader v = if decode_f64 v == 123.0
then read_f64
else read_f64LE
ftype_n :: Int -> (Int, Int)
ftype_n 1 = (2, 1)
ftype_n 2 = (3, 1)
ftype_n 3 = (2, 26)
ftype_n 4 = (3, 26)
ftype_n _ = undefined
atsSC3Indices :: ATSHeader -> [Int]
atsSC3Indices h =
let np = atsNPartials h
o = 3 * (np 1)
a = [1,4 .. (1 + o)]
f = map (+ 1) a
p = map (+ 1) f
n = map (+ (4+o)) [0..24]
in if atsFileType h == 4
then a ++ f ++ p ++ n
else error "atsSC3Indices: illegal ATS file type (/= 4)"