module Synthesizer.ALSA.Storable.Play (
Device,
defaultDevice,
defaultChunkSize,
makeSink,
write,
writeLazy,
auto,
autoAndRecord,
autoAndRecordMany,
monoToInt16,
stereoToInt16,
) where
import qualified Sound.ALSA.PCM as ALSA
import qualified Synthesizer.Frame.Stereo as Stereo
import qualified Synthesizer.Basic.Binary as BinSmp
import qualified Sound.Sox.Frame as SoxFrame
import qualified Sound.Sox.Write as SoxWrite
import qualified Sound.Sox.Option.Format as SoxOption
import Foreign.Storable (Storable, )
import Foreign.Marshal.Array (advancePtr, )
import Foreign.Ptr (Ptr, minusPtr, )
import Data.Int (Int16, )
import qualified System.IO as IO
import qualified System.Exit as Exit
import qualified Synthesizer.Storable.Signal as SigSt
import qualified Data.StorableVector.Lazy as SVL
import qualified Data.StorableVector.Base as SVB
import qualified Algebra.RealRing as RealRing
import qualified Data.Traversable as Trav
import qualified Data.Foldable as Fold
import NumericPrelude.Numeric
import NumericPrelude.Base
defaultChunkSize :: SigSt.ChunkSize
defaultChunkSize = SigSt.chunkSize 512
type Device = String
defaultDevice :: Device
defaultDevice = "default"
makeSink ::
(ALSA.SampleFmt y, RealRing.C t) =>
Device ->
t ->
ALSA.SampleFreq ->
ALSA.SoundSink ALSA.Pcm y
makeSink device periodTime rate =
ALSA.alsaSoundSinkTime device
(ALSA.SoundFmt {
ALSA.sampleFreq = rate
}) $
ALSA.SoundBufferTime
(round (5000000*periodTime))
(round (1000000*periodTime))
auto ::
(ALSA.SampleFmt y) =>
ALSA.SoundSink handle y ->
SigSt.T y -> IO ()
auto sink ys =
ALSA.withSoundSink sink $ \to ->
writeLazy sink to ys
writeLazy ::
(Storable y) =>
ALSA.SoundSink handle y -> handle y ->
SVL.Vector y -> IO ()
writeLazy sink to ys =
mapM_ (write sink to) (SVL.chunks ys)
write ::
(Storable y) =>
ALSA.SoundSink handle y -> handle y ->
SVB.Vector y -> IO ()
write sink to c =
SVB.withStartPtr c $ \ptr size ->
ALSA.soundSinkWrite sink to ptr size
arraySize :: Storable y => Ptr y -> Int -> Int
arraySize p n = advancePtr p n `minusPtr` p
autoAndRecord ::
(ALSA.SampleFmt y, SoxFrame.C y) =>
FilePath ->
ALSA.SoundFmt y ->
ALSA.SoundSink handle y ->
SigSt.T y -> IO Exit.ExitCode
autoAndRecord fileName fmt sink =
let rate = ALSA.sampleFreq fmt
in (\act ->
SoxWrite.simple act SoxOption.none fileName rate) $ \h ys ->
ALSA.withSoundSink sink $ \to ->
flip mapM_ (SVL.chunks ys) $ \c ->
SVB.withStartPtr c $ \ptr size ->
ALSA.soundSinkWrite sink to ptr size >>
IO.hPutBuf h ptr (arraySize ptr size)
autoAndRecordMany ::
(ALSA.SampleFmt y, SoxFrame.C y,
Trav.Traversable f) =>
f FilePath ->
ALSA.SoundFmt y ->
ALSA.SoundSink handle y ->
SigSt.T y -> IO (f Exit.ExitCode)
autoAndRecordMany fileNames fmt sink =
let rate = ALSA.sampleFreq fmt
in (\act ->
SoxWrite.manyExtended act SoxOption.none SoxOption.none fileNames rate) $ \hs ys ->
ALSA.withSoundSink sink $ \to ->
flip mapM_ (SVL.chunks ys) $ \c ->
SVB.withStartPtr c $ \ptr size ->
ALSA.soundSinkWrite sink to ptr size >>
Fold.traverse_ (\h -> IO.hPutBuf h ptr (arraySize ptr size)) hs
monoToInt16 ::
(Storable y, RealRing.C y) =>
ALSA.SoundSink handle Int16 ->
SigSt.T y -> IO ()
monoToInt16 sink xs =
auto sink (SigSt.map BinSmp.int16FromCanonical xs)
stereoToInt16 ::
(Storable y, RealRing.C y) =>
ALSA.SoundSink handle (Stereo.T Int16) ->
SigSt.T (Stereo.T y) -> IO ()
stereoToInt16 sink xs =
auto sink (SigSt.map (fmap BinSmp.int16FromCanonical) xs)