{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
module Synth.MixDown where
import qualified Control.Monad.Trans.Resource as Resource
import qualified Data.List as List
import qualified System.Directory as Directory
import qualified System.Environment as Environment
import qualified System.Exit as Exit
import System.FilePath ((</>))
import qualified System.IO as IO
import qualified Util.Audio.Audio as Audio
import qualified Util.Audio.File as Audio.File
import qualified Synth.Shared.Config as Config
import Global
main :: IO ()
main :: IO ()
main = do
([Char]
out, [[Char]]
dirs) <- IO [[Char]]
Environment.getArgs forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
[Char]
out : [[Char]]
dirs
| [Char]
".wav" forall a. Eq a => [a] -> [a] -> Bool
`List.isSuffixOf` [Char]
out -> forall (m :: * -> *) a. Monad m => a -> m a
return ([Char]
out, [[Char]]
dirs)
| Bool
otherwise -> forall a. [Char] -> IO a
usage [Char]
"out arg should be .wav!"
[] -> forall a. [Char] -> IO a
usage [Char]
""
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (forall (m :: * -> *) a. Monad m => (a -> m Bool) -> [a] -> m Bool
allM [Char] -> IO Bool
Directory.doesDirectoryExist [[Char]]
dirs) forall a b. (a -> b) -> a -> b
$
forall a. [Char] -> IO a
usage [Char]
"non-directory arg"
[AudioIO SamplingRate 2]
streams <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM [Char] -> IO (AudioIO SamplingRate 2)
streamDir [[Char]]
dirs
forall (m :: * -> *) a. MonadUnliftIO m => ResourceT m a -> m a
Resource.runResourceT forall a b. (a -> b) -> a -> b
$ forall (rate :: Nat) (chan :: Nat).
(KnownNat rate, KnownNat chan) =>
Format -> [Char] -> AudioIO rate chan -> ResourceT IO ()
Audio.File.write Format
Audio.File.wavFormat [Char]
out forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) (rate :: Nat) (chan :: Nat).
Monad m =>
[Audio m rate chan] -> Audio m rate chan
Audio.mix [AudioIO SamplingRate 2]
streams
usage :: String -> IO a
usage :: forall a. [Char] -> IO a
usage [Char]
msg = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
msg) forall a b. (a -> b) -> a -> b
$
Handle -> [Char] -> IO ()
IO.hPutStrLn Handle
IO.stderr forall a b. (a -> b) -> a -> b
$ [Char]
"error: " forall a. Semigroup a => a -> a -> a
<> [Char]
msg
Handle -> [Char] -> IO ()
IO.hPutStrLn Handle
IO.stderr forall a b. (a -> b) -> a -> b
$ [Char]
"usage: mixdown out.wav [ dir1 dir2 ... ]"
forall a. IO a
Exit.exitFailure
streamDir :: FilePath -> IO (Audio.AudioIO Config.SamplingRate 2)
streamDir :: [Char] -> IO (AudioIO SamplingRate 2)
streamDir [Char]
dir = do
[[Char]]
chunks <- forall a. Ord a => [a] -> [a]
List.sort forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter ([Char]
".wav" `List.isSuffixOf`) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
[Char] -> IO [[Char]]
Directory.listDirectory [Char]
dir
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Char]]
chunks) forall a b. (a -> b) -> a -> b
$
Handle -> [Char] -> IO ()
IO.hPutStrLn Handle
IO.stderr forall a b. (a -> b) -> a -> b
$ [Char]
"WARNING: no *.wav in " forall a. Semigroup a => a -> a -> a
<> [Char]
dir
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rate :: Nat) (chan :: Nat).
(KnownNat rate, KnownNat chan) =>
Frames -> [[Char]] -> AudioIO rate chan
Audio.File.readCheckpoints Frames
Config.chunkSize (forall a b. (a -> b) -> [a] -> [b]
map ([Char]
dir</>) [[Char]]
chunks)