module Synthesizer.LLVM.Server.SampledSound where import Synthesizer.LLVM.Server.Common (Real) import qualified Sound.Sox.Read as SoxRead import qualified Sound.Sox.Option.Format as SoxOption import Control.Exception (bracket) import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector.Lazy as SVL import qualified System.Path.PartClass as PathClass import qualified System.Path as Path import System.Path (()) import Data.Tuple.HT (mapPair) import qualified Number.DimensionTerm as DN import Prelude hiding (Real, length) data T = Cons { body :: SigSt.T Real, sampleRate :: DN.Frequency Real, positions :: Positions } data Positions = Positions { start, length, loopStart, loopLength :: Int, period :: Real } -- ToDo: flag failure if files cannot be found, or just remain silent load :: (PathClass.AbsRel ar) => Path.File ar -> IO (SVL.Vector Real) load path = bracket (SoxRead.open SoxOption.none (Path.toString path)) SoxRead.close $ SoxRead.withHandle1 (SVL.hGetContentsSync SVL.defaultChunkSize) loadRanges :: (PathClass.AbsRel ar) => Path.Dir ar -> Info -> IO [T] loadRanges dir (Info file sr poss) = fmap (\smp -> map (Cons smp (DN.frequency sr)) poss) (load (dir file)) data Info = Info { infoName :: Path.RelFile, infoRate :: Real, infoPositions :: [Positions] } info :: FilePath -> Real -> [Positions] -> Info info path = Info (Path.relFile path) parts :: T -> (SigSt.T Real, SigSt.T Real, SigSt.T Real) parts smp = let pos = positions smp (attack,sustain) = mapPair (SigSt.drop (start pos), SigSt.take (loopLength pos)) $ SigSt.splitAt (loopStart pos) $ body smp release = SigSt.drop (loopStart pos + loopLength pos) $ SigSt.take (start pos + length pos) $ body smp in (attack, sustain, release) -- * examples tomatensalatPositions :: [Positions] tomatensalatPositions = Positions 0 29499 12501 15073 321.4 : Positions 29499 31672 38163 17312 320.6 : Positions 67379 28610 81811 10667 323.2 : Positions 95989 31253 106058 16111 323.7 : {- vor dem 't' kommt noch das Ende vom 'a' wir bräuchten eine weitere Positionsangabe, um am Ende etwas überspringen zu können. Ein Smart-Konstruktor wie 'positions' könnte das bisherige Verhalten nachmachen. -} Positions 127242 38596 136689 11514 319.3 : [] tomatensalat :: Info tomatensalat = info "tomatensalat2.wav" 44100 tomatensalatPositions halPositions :: [Positions] halPositions = -- Positions 2371 25957 7362 6321 : Positions 2371 25957 (2371+25957) 1 320 : Positions 40546 34460 63540 9546 317.4 : Positions 79128 32348 94367 14016 317.8 : Positions 112027 21227 125880 5500 322.5 : Positions 146057 23235 168941 352 320 : [] hal :: Info hal = info "haskell-in-leipzig2.wav" 44100 halPositions graphentheoriePositions :: [Positions] graphentheoriePositions = Positions 0 29524 13267 14768 301.1 : Positions 29524 35333 47624 9968 301.6 : Positions 64857 31189 73818 16408 297.3 : Positions 96046 31312 106206 18504 302.9 : Positions 127358 32127 132469 16530 299.4 : [] graphentheorie :: Info graphentheorie = info "graphentheorie0.wav" 44100 graphentheoriePositions