alsa-pcm 0.5.0.1 → 0.6
raw patch · 20 files changed
+2037/−1019 lines, 20 filesdep +containersdep +storable-recorddep +transformersdep ~alsa-seqdep ~arraynew-component:exe:alsa-sinePVP ok
version bump matches the API change (PVP)
Dependencies added: containers, storable-record, transformers
Dependency ranges changed: alsa-seq, array
API changes (from Hackage documentation)
- Sound.ALSA.PCM: data Pcm
- Sound.ALSA.PCM: instance SampleFmt Double
- Sound.ALSA.PCM: instance SampleFmt Float
- Sound.ALSA.PCM: instance SampleFmt Int16
- Sound.ALSA.PCM: instance SampleFmt Int32
- Sound.ALSA.PCM: instance SampleFmt Int8
- Sound.ALSA.PCM: instance SampleFmt T
- Sound.ALSA.PCM: instance SampleFmt Word16
- Sound.ALSA.PCM: instance SampleFmt Word32
- Sound.ALSA.PCM: instance SampleFmt Word8
- Sound.ALSA.PCM: instance SampleFmt a => SampleFmt (T a)
- Sound.ALSA.PCM: soundSinkFmt :: SoundSink y handle -> SoundFmt y
- Sound.ALSA.PCM: soundSourceFmt :: SoundSource y handle -> SoundFmt y
+ Sound.ALSA.PCM: alsaSoundSinkParams :: SampleFmt y => String -> T Interleaved y a -> (a -> T Interleaved y ()) -> SoundSink Pcm y
+ Sound.ALSA.PCM: alsaSoundSourceParams :: SampleFmt y => String -> T Interleaved y a -> (a -> T Interleaved y ()) -> SoundSource Pcm y
+ Sound.ALSA.PCM: type File = Handle
+ Sound.ALSA.PCM: type Pcm = Handle Interleaved
+ Sound.ALSA.PCM: type Size = Int
+ Sound.ALSA.PCM.Node.ALSA: StreamCapture :: Stream
+ Sound.ALSA.PCM.Node.ALSA: StreamPlayback :: Stream
+ Sound.ALSA.PCM.Node.ALSA: async :: Mode
+ Sound.ALSA.PCM.Node.ALSA: class Access i
+ Sound.ALSA.PCM.Node.ALSA: class SampleFmt y => MonoSampleFmt y
+ Sound.ALSA.PCM.Node.ALSA: class (Storable y, C y) => SampleFmt y
+ Sound.ALSA.PCM.Node.ALSA: close :: Handle i y -> IO ()
+ Sound.ALSA.PCM.Node.ALSA: data Handle i y
+ Sound.ALSA.PCM.Node.ALSA: data Interleaved
+ Sound.ALSA.PCM.Node.ALSA: data Mode
+ Sound.ALSA.PCM.Node.ALSA: data Noninterleaved
+ Sound.ALSA.PCM.Node.ALSA: data Stream
+ Sound.ALSA.PCM.Node.ALSA: drain :: Handle i y -> IO ()
+ Sound.ALSA.PCM.Node.ALSA: drop :: Handle i y -> IO ()
+ Sound.ALSA.PCM.Node.ALSA: modes :: [Mode] -> Mode
+ Sound.ALSA.PCM.Node.ALSA: nonBlock :: Mode
+ Sound.ALSA.PCM.Node.ALSA: open :: (Access i, SampleFmt y) => Mode -> Stream -> T i y a -> (a -> T i y b) -> String -> IO (b, Handle i y)
+ Sound.ALSA.PCM.Node.ALSA: prepare :: Handle i y -> IO ()
+ Sound.ALSA.PCM.Node.ALSA: readi :: SampleFmt y => Handle Interleaved y -> Ptr y -> Size -> IO Size
+ Sound.ALSA.PCM.Node.ALSA: readiRetry :: SampleFmt y => Handle Interleaved y -> Ptr y -> Size -> IO Size
+ Sound.ALSA.PCM.Node.ALSA: readn :: MonoSampleFmt y => Handle Noninterleaved y -> Ptr (Ptr y) -> Size -> IO Size
+ Sound.ALSA.PCM.Node.ALSA: start :: Handle i y -> IO ()
+ Sound.ALSA.PCM.Node.ALSA: type SampleFreq = Int
+ Sound.ALSA.PCM.Node.ALSA: type Size = Int
+ Sound.ALSA.PCM.Node.ALSA: type Time = Int
+ Sound.ALSA.PCM.Node.ALSA: writei :: SampleFmt y => Handle Interleaved y -> Ptr y -> Size -> IO Size
+ Sound.ALSA.PCM.Node.ALSA: writeiRetry :: SampleFmt y => Handle Interleaved y -> Ptr y -> Size -> IO Size
+ Sound.ALSA.PCM.Node.ALSA: writen :: MonoSampleFmt y => Handle Noninterleaved y -> Ptr (Ptr y) -> Size -> IO Size
+ Sound.ALSA.PCM.Node.File: class (Storable y, C y) => SampleFmt y
+ Sound.ALSA.PCM.Node.File: close :: SampleFmt y => Handle y -> IO ()
+ Sound.ALSA.PCM.Node.File: data Handle y
+ Sound.ALSA.PCM.Node.File: open :: SampleFmt y => IOMode -> FilePath -> IO (Handle y)
+ Sound.ALSA.PCM.Node.File: read :: SampleFmt y => Handle y -> Ptr y -> Size -> IO Size
+ Sound.ALSA.PCM.Node.File: type SampleFreq = Int
+ Sound.ALSA.PCM.Node.File: type Size = Int
+ Sound.ALSA.PCM.Node.File: type Time = Int
+ Sound.ALSA.PCM.Node.File: write :: SampleFmt y => Handle y -> Ptr y -> Size -> IO ()
+ Sound.ALSA.PCM.Parameters.Hardware: canMmapSampleResolution :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: canOverrange :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: canPause :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: canResume :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: canSyncStart :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: data Interleaved
+ Sound.ALSA.PCM.Parameters.Hardware: data Noninterleaved
+ Sound.ALSA.PCM.Parameters.Hardware: data T i y a
+ Sound.ALSA.PCM.Parameters.Hardware: getBufferSize :: T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: getBufferSizeMax :: T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: getBufferSizeMin :: T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: getBufferTime :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getBufferTimeMax :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getBufferTimeMin :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getChannels :: T i y (Word)
+ Sound.ALSA.PCM.Parameters.Hardware: getChannelsMax :: T i y (Word)
+ Sound.ALSA.PCM.Parameters.Hardware: getChannelsMin :: T i y (Word)
+ Sound.ALSA.PCM.Parameters.Hardware: getExportBuffer :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: getFifoSize :: T i y (Word)
+ Sound.ALSA.PCM.Parameters.Hardware: getMinAlign :: T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodSize :: T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodSizeMax :: T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodSizeMin :: T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodTime :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodTimeMax :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodTimeMin :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriods :: T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodsMax :: T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getPeriodsMin :: T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getRate :: T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getRateMax :: T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getRateMin :: T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getRateNumden :: T i y (Word, Word)
+ Sound.ALSA.PCM.Parameters.Hardware: getRateResample :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: getSbits :: T i y (Word)
+ Sound.ALSA.PCM.Parameters.Hardware: getTickTime :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getTickTimeMax :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: getTickTimeMin :: T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: isBatch :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: isBlockTransfer :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: isDouble :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: isHalfDuplex :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: isJointDuplex :: T i y (Bool)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSize :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSizeFirst :: Size -> T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSizeLast :: Size -> T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSizeMax :: Size -> T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSizeMin :: Size -> T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSizeMinmax :: Size -> Size -> T i y (Size, Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferSizeNear :: Size -> T i y (Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTime :: Time -> Ordering -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTimeFirst :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTimeLast :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTimeMax :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTimeMin :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTimeMinmax :: Time -> Ordering -> Time -> Ordering -> T i y (Time, Ordering, Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setBufferTimeNear :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setChannels :: Word -> T Noninterleaved y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setChannelsFirst :: Word -> T Noninterleaved y Word
+ Sound.ALSA.PCM.Parameters.Hardware: setChannelsLast :: Word -> T Noninterleaved y Word
+ Sound.ALSA.PCM.Parameters.Hardware: setChannelsMax :: Word -> T Noninterleaved y Word
+ Sound.ALSA.PCM.Parameters.Hardware: setChannelsMin :: Word -> T Noninterleaved y Word
+ Sound.ALSA.PCM.Parameters.Hardware: setChannelsMinmax :: Word -> Word -> T Noninterleaved y (Word, Word)
+ Sound.ALSA.PCM.Parameters.Hardware: setChannelsNear :: Word -> T Noninterleaved y Word
+ Sound.ALSA.PCM.Parameters.Hardware: setExportBuffer :: Bool -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSize :: Size -> Ordering -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeFirst :: Size -> Ordering -> T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeInteger :: T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeLast :: Size -> Ordering -> T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeMax :: Size -> Ordering -> T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeMin :: Size -> Ordering -> T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeMinmax :: Size -> Ordering -> Size -> Ordering -> T i y (Size, Ordering, Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodSizeNear :: Size -> Ordering -> T i y (Size, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTime :: Time -> Ordering -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTimeFirst :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTimeLast :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTimeMax :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTimeMin :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTimeMinmax :: Time -> Ordering -> Time -> Ordering -> T i y (Time, Ordering, Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodTimeNear :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriods :: Word -> Ordering -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsFirst :: Word -> Ordering -> T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsInteger :: T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsLast :: Word -> Ordering -> T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsMax :: Word -> Ordering -> T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsMin :: Word -> Ordering -> T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsMinmax :: Word -> Ordering -> Word -> Ordering -> T i y (Word, Ordering, Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setPeriodsNear :: Word -> Ordering -> T i y (Word, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRate :: SampleFreq -> Ordering -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setRateBufferTime :: SampleFreq -> Time -> Time -> T Interleaved y (Size, Size)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateFirst :: SampleFreq -> Ordering -> T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateLast :: SampleFreq -> Ordering -> T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateMax :: SampleFreq -> Ordering -> T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateMin :: SampleFreq -> Ordering -> T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateMinmax :: SampleFreq -> Ordering -> SampleFreq -> Ordering -> T i y (SampleFreq, Ordering, SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateNear :: SampleFreq -> Ordering -> T i y (SampleFreq, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setRateResample :: Bool -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTime :: Time -> Ordering -> T i y ()
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTimeFirst :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTimeLast :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTimeMax :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTimeMin :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTimeMinmax :: Time -> Ordering -> Time -> Ordering -> T i y (Time, Ordering, Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: setTickTimeNear :: Time -> Ordering -> T i y (Time, Ordering)
+ Sound.ALSA.PCM.Parameters.Hardware: testBufferSize :: Size -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testBufferTime :: Time -> Ordering -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testChannels :: Word -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testPeriodSize :: Size -> Ordering -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testPeriodTime :: Time -> Ordering -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testPeriods :: Word -> Ordering -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testRate :: SampleFreq -> Ordering -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: testTickTime :: Time -> Ordering -> T i y (Errno)
+ Sound.ALSA.PCM.Parameters.Hardware: type SampleFreq = Int
+ Sound.ALSA.PCM.Parameters.Hardware: type Size = Int
+ Sound.ALSA.PCM.Parameters.Hardware: type Time = Int
+ Sound.ALSA.PCM.Parameters.Software: data T i y a
+ Sound.ALSA.PCM.Parameters.Software: data TimestampMode
+ Sound.ALSA.PCM.Parameters.Software: getAvailMin :: T i y Size
+ Sound.ALSA.PCM.Parameters.Software: getSilenceSize :: T i y Size
+ Sound.ALSA.PCM.Parameters.Software: getSilenceThreshold :: T i y Size
+ Sound.ALSA.PCM.Parameters.Software: getSleepMin :: T i y Word
+ Sound.ALSA.PCM.Parameters.Software: getStartThreshold :: T i y Size
+ Sound.ALSA.PCM.Parameters.Software: getStopThreshold :: T i y Size
+ Sound.ALSA.PCM.Parameters.Software: getTimestampMode :: T i y TimestampMode
+ Sound.ALSA.PCM.Parameters.Software: getXferAlign :: T i y Size
+ Sound.ALSA.PCM.Parameters.Software: setAvailMin :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setBufferSize :: Size -> Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setSilenceSize :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setSilenceThreshold :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setSleepMin :: Word -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setStartThreshold :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setStopThreshold :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setTimestampMode :: TimestampMode -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: setXferAlign :: Size -> T i y ()
+ Sound.ALSA.PCM.Parameters.Software: timestampMmap :: TimestampMode
+ Sound.ALSA.PCM.Parameters.Software: timestampNone :: TimestampMode
+ Sound.ALSA.PCM.Parameters.Software: type Size = Int
- Sound.ALSA.PCM: SoundSink :: SoundFmt y -> IO handle -> (handle -> IO ()) -> (handle -> Ptr y -> Int -> IO ()) -> (handle -> IO ()) -> (handle -> IO ()) -> SoundSink y handle
+ Sound.ALSA.PCM: SoundSink :: IO (handle y) -> (handle y -> IO ()) -> (handle y -> Ptr y -> Size -> IO ()) -> (handle y -> IO ()) -> (handle y -> IO ()) -> SoundSink handle y
- Sound.ALSA.PCM: SoundSource :: SoundFmt y -> IO handle -> (handle -> IO ()) -> (handle -> IO ()) -> (handle -> IO ()) -> (handle -> Ptr y -> Int -> IO Int) -> SoundSource y handle
+ Sound.ALSA.PCM: SoundSource :: IO (handle y) -> (handle y -> IO ()) -> (handle y -> IO ()) -> (handle y -> IO ()) -> (handle y -> Ptr y -> Size -> IO Size) -> SoundSource handle y
- Sound.ALSA.PCM: alsaSoundSink :: SampleFmt y => String -> SoundFmt y -> SoundSink y Pcm
+ Sound.ALSA.PCM: alsaSoundSink :: SampleFmt y => String -> SoundFmt y -> SoundSink Pcm y
- Sound.ALSA.PCM: alsaSoundSinkTime :: SampleFmt y => String -> SoundFmt y -> SoundBufferTime -> SoundSink y Pcm
+ Sound.ALSA.PCM: alsaSoundSinkTime :: SampleFmt y => String -> SoundFmt y -> SoundBufferTime -> SoundSink Pcm y
- Sound.ALSA.PCM: alsaSoundSource :: SampleFmt y => String -> SoundFmt y -> SoundSource y Pcm
+ Sound.ALSA.PCM: alsaSoundSource :: SampleFmt y => String -> SoundFmt y -> SoundSource Pcm y
- Sound.ALSA.PCM: alsaSoundSourceTime :: SampleFmt y => String -> SoundFmt y -> SoundBufferTime -> SoundSource y Pcm
+ Sound.ALSA.PCM: alsaSoundSourceTime :: SampleFmt y => String -> SoundFmt y -> SoundBufferTime -> SoundSource Pcm y
- Sound.ALSA.PCM: copySound :: SampleFmt y => SoundSource y h1 -> SoundSink y h2 -> Int -> IO ()
+ Sound.ALSA.PCM: copySound :: SampleFmt y => SoundSource handleIn y -> SoundSink handleOut y -> Size -> IO ()
- Sound.ALSA.PCM: data SoundSink y handle
+ Sound.ALSA.PCM: data SoundSink handle y
- Sound.ALSA.PCM: data SoundSource y handle
+ Sound.ALSA.PCM: data SoundSource handle y
- Sound.ALSA.PCM: fileSoundSink :: SampleFmt y => FilePath -> SoundFmt y -> SoundSink y Handle
+ Sound.ALSA.PCM: fileSoundSink :: SampleFmt y => FilePath -> SoundSink File y
- Sound.ALSA.PCM: fileSoundSource :: SampleFmt y => FilePath -> SoundFmt y -> SoundSource y Handle
+ Sound.ALSA.PCM: fileSoundSource :: SampleFmt y => FilePath -> SoundSource File y
- Sound.ALSA.PCM: soundSinkBytesPerFrame :: SampleFmt y => SoundSink y h -> Int
+ Sound.ALSA.PCM: soundSinkBytesPerFrame :: SampleFmt y => SoundSink handle y -> Int
- Sound.ALSA.PCM: soundSinkClose :: SoundSink y handle -> handle -> IO ()
+ Sound.ALSA.PCM: soundSinkClose :: SoundSink handle y -> handle y -> IO ()
- Sound.ALSA.PCM: soundSinkOpen :: SoundSink y handle -> IO handle
+ Sound.ALSA.PCM: soundSinkOpen :: SoundSink handle y -> IO (handle y)
- Sound.ALSA.PCM: soundSinkStart :: SoundSink y handle -> handle -> IO ()
+ Sound.ALSA.PCM: soundSinkStart :: SoundSink handle y -> handle y -> IO ()
- Sound.ALSA.PCM: soundSinkStop :: SoundSink y handle -> handle -> IO ()
+ Sound.ALSA.PCM: soundSinkStop :: SoundSink handle y -> handle y -> IO ()
- Sound.ALSA.PCM: soundSinkWrite :: SoundSink y handle -> handle -> Ptr y -> Int -> IO ()
+ Sound.ALSA.PCM: soundSinkWrite :: SoundSink handle y -> handle y -> Ptr y -> Size -> IO ()
- Sound.ALSA.PCM: soundSourceBytesPerFrame :: SampleFmt y => SoundSource y h -> Int
+ Sound.ALSA.PCM: soundSourceBytesPerFrame :: SampleFmt y => SoundSource handle y -> Int
- Sound.ALSA.PCM: soundSourceClose :: SoundSource y handle -> handle -> IO ()
+ Sound.ALSA.PCM: soundSourceClose :: SoundSource handle y -> handle y -> IO ()
- Sound.ALSA.PCM: soundSourceOpen :: SoundSource y handle -> IO handle
+ Sound.ALSA.PCM: soundSourceOpen :: SoundSource handle y -> IO (handle y)
- Sound.ALSA.PCM: soundSourceRead :: SoundSource y handle -> handle -> Ptr y -> Int -> IO Int
+ Sound.ALSA.PCM: soundSourceRead :: SoundSource handle y -> handle y -> Ptr y -> Size -> IO Size
- Sound.ALSA.PCM: soundSourceStart :: SoundSource y handle -> handle -> IO ()
+ Sound.ALSA.PCM: soundSourceStart :: SoundSource handle y -> handle y -> IO ()
- Sound.ALSA.PCM: soundSourceStop :: SoundSource y handle -> handle -> IO ()
+ Sound.ALSA.PCM: soundSourceStop :: SoundSource handle y -> handle y -> IO ()
- Sound.ALSA.PCM: withSoundSink :: SoundSink y h -> (h -> IO a) -> IO a
+ Sound.ALSA.PCM: withSoundSink :: SoundSink handle y -> (handle y -> IO a) -> IO a
- Sound.ALSA.PCM: withSoundSinkRunning :: SoundSink y h -> h -> IO a -> IO a
+ Sound.ALSA.PCM: withSoundSinkRunning :: SoundSink handle y -> handle y -> IO a -> IO a
- Sound.ALSA.PCM: withSoundSource :: SoundSource y h -> (h -> IO a) -> IO a
+ Sound.ALSA.PCM: withSoundSource :: SoundSource handle y -> (handle y -> IO a) -> IO a
- Sound.ALSA.PCM: withSoundSourceRunning :: SoundSource y h -> h -> IO a -> IO a
+ Sound.ALSA.PCM: withSoundSourceRunning :: SoundSource handle y -> handle y -> IO a -> IO a
Files
- alsa-pcm.cabal +100/−42
- examples/duplex.hs +5/−5
- examples/play.hs +1/−1
- examples/record.hs +3/−3
- examples/sine.hs +88/−0
- examples/synth.hs +70/−83
- examples/volume_meter.hs +4/−4
- src/Sound/ALSA/PCM.hs +216/−328
- src/Sound/ALSA/PCM/C2HS.hs +0/−237
- src/Sound/ALSA/PCM/Core.chs +0/−316
- src/Sound/ALSA/PCM/Core/Class.hs +107/−0
- src/Sound/ALSA/PCM/Core/Convert.hs +34/−0
- src/Sound/ALSA/PCM/Core/Handle.hsc +157/−0
- src/Sound/ALSA/PCM/Core/HwParams.hsc +382/−0
- src/Sound/ALSA/PCM/Core/Params.h +247/−0
- src/Sound/ALSA/PCM/Core/SwParams.hsc +138/−0
- src/Sound/ALSA/PCM/Node/ALSA.hs +126/−0
- src/Sound/ALSA/PCM/Node/File.hs +60/−0
- src/Sound/ALSA/PCM/Parameters/Hardware.hs +262/−0
- src/Sound/ALSA/PCM/Parameters/Software.hs +37/−0
alsa-pcm.cabal view
@@ -1,5 +1,5 @@ Name: alsa-pcm-Version: 0.5.0.1+Version: 0.6 Copyright: Bjorn Bringert, Iavor S. Diatchki, Henning Thielemann Maintainer: Henning Thielemann <alsa@henning-thielemann.de> Author: Henning Thielemann <alsa@henning-thielemann.de>, Bjorn Bringert <bjorn@bringert.net>, Iavor S. Diatchki <iavor.diatchki@gmail.com>@@ -19,6 +19,7 @@ Extra-Source-Files: nodebug/Sound/ALSA/PCM/Debug.hs debug/Sound/ALSA/PCM/Debug.hs+ src/Sound/ALSA/PCM/Core/Params.h Source-Repository head type: darcs@@ -27,7 +28,7 @@ Source-Repository this type: darcs location: http://code.haskell.org/alsa/pcm/- tag: 0.5.0.1+ tag: 0.6 Flag buildExamples description: Build example executables@@ -44,12 +45,14 @@ Library Build-depends: alsa-core >=0.5 && <0.6,+ storable-record >=0.0.2 && <0.1, sample-frame >=0.0.1 && <0.1,- array >= 0.1 && <0.4,+ array >= 0.1 && <0.5, extensible-exceptions >=0.1.1 && <0.2, base >= 3 && <5 Hs-Source-Dirs: src+ Include-Dirs: src If flag(debug) Hs-Source-Dirs: debug Else@@ -57,10 +60,17 @@ Exposed-Modules: Sound.ALSA.PCM+ Sound.ALSA.PCM.Node.ALSA+ Sound.ALSA.PCM.Node.File+ Sound.ALSA.PCM.Parameters.Hardware+ Sound.ALSA.PCM.Parameters.Software Other-modules:- Sound.ALSA.PCM.Core- Sound.ALSA.PCM.C2HS+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.Convert+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams Sound.ALSA.PCM.Debug GHC-Options: -Wall -fwarn-tabs@@ -70,77 +80,125 @@ Executable alsa-minisynth Main-Is: synth.hs- If !flag(buildSynthesizer)+ If flag(buildSynthesizer)+ Build-Depends:+ alsa-seq >=0.6 && <0.7,+ alsa-core >=0.5 && <0.6,+ containers >=0.2 && <0.5,+ transformers >=0.2 && <0.4,+ storablevector >=0.2.7 && <0.3,+ storable-record >=0.0.2 && <0.1,+ sample-frame >=0.0.1 && <0.1,+ base >=3 && <5+ Else Buildable: False Hs-Source-Dirs: src, debug, examples+ Include-Dirs: src GHC-Options: -Wall -threaded Other-modules: Sound.ALSA.PCM- Sound.ALSA.PCM.Core- Sound.ALSA.PCM.C2HS- Build-Depends:- alsa-seq >=0.5 && <0.6,- alsa-core >=0.5 && <0.6,- storablevector >=0.2.7 && <0.3,- sample-frame >=0.0.1 && <0.1,- base >=3 && <5+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams +Executable alsa-sine+ Main-Is: sine.hs+ If flag(buildSynthesizer)+ Build-Depends:+ alsa-core >=0.5 && <0.6,+ storablevector >=0.2.7 && <0.3,+ storable-record >=0.0.2 && <0.1,+ sample-frame >=0.0.1 && <0.1,+ base >=3 && <5+ Else+ Buildable: False+ Hs-Source-Dirs: src, debug, examples+ Include-Dirs: src+ GHC-Options: -Wall -threaded+ Other-modules:+ Sound.ALSA.PCM+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams+ Executable alsa-duplex Main-Is: duplex.hs- If !flag(buildExamples)+ If flag(buildExamples)+ Build-Depends:+ alsa-core >=0.5 && <0.6,+ storable-record >=0.0.2 && <0.1,+ sample-frame >=0.0.1 && <0.1,+ base >=3 && <5+ Else Buildable: False Hs-Source-Dirs: src, debug, examples+ Include-Dirs: src GHC-Options: -Wall -threaded Other-modules: Sound.ALSA.PCM- Sound.ALSA.PCM.Core- Sound.ALSA.PCM.C2HS- Build-Depends:- alsa-core >=0.5 && <0.6,- sample-frame >=0.0.1 && <0.1,- base >=3 && <5+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams Executable alsa-play Main-Is: play.hs- If !flag(buildExamples)+ If flag(buildExamples)+ Build-Depends:+ alsa-core >=0.5 && <0.6,+ storable-record >=0.0.2 && <0.1,+ sample-frame >=0.0.1 && <0.1,+ base >=3 && <5+ Else Buildable: False Hs-Source-Dirs: src, debug, examples+ Include-Dirs: src GHC-Options: -Wall -threaded Other-modules: Sound.ALSA.PCM- Sound.ALSA.PCM.Core- Sound.ALSA.PCM.C2HS- Build-Depends:- alsa-core >=0.5 && <0.6,- sample-frame >=0.0.1 && <0.1,- base >=3 && <5+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams Executable alsa-record Main-Is: record.hs- If !flag(buildExamples)+ If flag(buildExamples)+ Build-Depends:+ alsa-core >=0.5 && <0.6,+ storable-record >=0.0.2 && <0.1,+ sample-frame >=0.0.1 && <0.1,+ base >=3 && <5+ Else Buildable: False Hs-Source-Dirs: src, debug, examples+ Include-Dirs: src GHC-Options: -Wall -threaded Other-modules: Sound.ALSA.PCM- Sound.ALSA.PCM.Core- Sound.ALSA.PCM.C2HS- Build-Depends:- alsa-core >=0.5 && <0.6,- sample-frame >=0.0.1 && <0.1,- base >=3 && <5+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams Executable alsa-volume-meter Main-Is: volume_meter.hs- If !flag(buildExamples)+ If flag(buildExamples)+ Build-Depends:+ alsa-core >=0.5 && <0.6,+ storable-record >=0.0.2 && <0.1,+ sample-frame >=0.0.1 && <0.1,+ base >=3 && <5+ Else Buildable: False Hs-Source-Dirs: src, debug, examples+ Include-Dirs: src GHC-Options: -Wall -threaded Other-modules: Sound.ALSA.PCM- Sound.ALSA.PCM.Core- Sound.ALSA.PCM.C2HS- Build-Depends:- alsa-core >=0.5 && <0.6,- sample-frame >=0.0.1 && <0.1,- base >=3 && <5+ Sound.ALSA.PCM.Core.Class+ Sound.ALSA.PCM.Core.Handle+ Sound.ALSA.PCM.Core.HwParams+ Sound.ALSA.PCM.Core.SwParams
examples/duplex.hs view
@@ -13,7 +13,7 @@ bufSize = 4096 soundFormat :: SoundFmt Int16-soundFormat = SoundFmt { sampleFreq = 8000 }+soundFormat = SoundFmt { sampleFreq = 8000 } main :: IO () main = do args <- getArgs@@ -32,12 +32,12 @@ play :: FilePath -> IO () play file =- do let source = fileSoundSource file soundFormat- sink = alsaSoundSink "plughw:0,0" soundFormat+ do let source = fileSoundSource file+ sink = alsaSoundSink "default" soundFormat copySound source sink bufSize record :: FilePath -> IO () record file =- do let source = alsaSoundSource "plughw:0,0" soundFormat- sink = fileSoundSink file soundFormat+ do let source = alsaSoundSource "default" soundFormat+ sink = fileSoundSink file copySound source sink bufSize
examples/play.hs view
@@ -19,7 +19,7 @@ play :: FilePath -> IO () play file = copySound- (fileSoundSource file soundFormat)+ (fileSoundSource file) -- "default" allows mixing with other ALSA programs (alsaSoundSink "default" soundFormat) bufSize
examples/record.hs view
@@ -11,7 +11,7 @@ bufSize = 8192 soundFormat :: SoundFmt Int16-soundFormat = SoundFmt { sampleFreq = 8000 }+soundFormat = SoundFmt { sampleFreq = 8000 } main :: IO () main = do args <- getArgs@@ -22,6 +22,6 @@ record :: FilePath -> IO () record file =- do let source = alsaSoundSource "plughw:0,0" soundFormat- sink = fileSoundSink file soundFormat+ do let source = alsaSoundSource "default" soundFormat+ sink = fileSoundSink file copySound source sink bufSize
+ examples/sine.hs view
@@ -0,0 +1,88 @@+{- |+Demonstrate how to adapt to the parameters 'sample rate' and 'buffer size'+that are supported natively by the hardware.+-}+import qualified Sound.ALSA.PCM.Node.ALSA as PCM+import qualified Sound.ALSA.PCM.Parameters.Software as SwParam+import qualified Sound.ALSA.PCM.Parameters.Hardware as HwParam++import qualified Sound.ALSA.PCM.Debug as Debug++import qualified Data.StorableVector.Lazy as SVL+import qualified Data.StorableVector.Base as SVB++import Control.Exception (bracket, )++++openPCM ::+ (PCM.Access i, PCM.SampleFmt y) =>+ IO (PCM.Size, PCM.SampleFreq, PCM.Handle i y)+openPCM = do+ Debug.put "alsaOpenTest"+ (((bufferSize,periodSize),(bufferTime,periodTime),sampleRate), h) <-+ PCM.open (PCM.modes []) PCM.StreamPlayback+ (setHwParams 44100 1024 64)+ (\q@(sizes,_,_) -> do+ uncurry SwParam.setBufferSize sizes+ return q)+ "plughw:0"+ PCM.prepare h+ Debug.put $ "bufferTime = " ++ show bufferTime+ Debug.put $ "bufferSize = " ++ show bufferSize+ Debug.put $ "periodTime = " ++ show periodTime+ Debug.put $ "periodSize = " ++ show periodSize+ return (periodSize, sampleRate, h)++closePCM :: (PCM.Size, PCM.SampleFreq, PCM.Handle i y) -> IO ()+closePCM (_,_,pcm) = do+ Debug.put "alsaClose"+ PCM.drain pcm+ PCM.close pcm++setHwParams ::+ PCM.SampleFreq -- ^ sample frequency+ -> PCM.Size -- ^ buffer size+ -> PCM.Size -- ^ period size+ -> HwParam.T i y ((PCM.Size,PCM.Size),(PCM.Time,PCM.Time),PCM.SampleFreq)+ -- ^ ((bufferSize,periodSize),(bufferTime,periodTime),sampleRate)+setHwParams rate bufferSize periodSize = do+{-+ (actualRate,ord) <- HwParam.getRateMax+ print ord+-}+ HwParam.setRateResample False+ (actualRate,_) <-+ HwParam.setRateNear rate EQ+ (actualPeriodSize,_) <-+ HwParam.setPeriodSizeNear periodSize EQ+ actualBufferSize <-+ HwParam.setBufferSizeNear+ (max bufferSize (actualPeriodSize*2))+{-+ let actualBufferSize = bufferSize+ HwParam.setBufferSize bufferSize+-}+ (actualBufferTime,_) <- HwParam.getBufferTime+ (actualPeriodTime,_) <- HwParam.getPeriodTime+ return ((actualBufferSize, actualPeriodSize),+ (actualBufferTime, actualPeriodTime),+ actualRate)++write ::+ (PCM.SampleFmt y) =>+ PCM.Handle PCM.Interleaved y -> SVB.Vector y -> IO ()+write h xs =+ SVB.withStartPtr xs $ \buf ->+ fmap (const ()) . PCM.writeiRetry h buf . fromIntegral+++main :: IO ()+main =+ bracket openPCM closePCM $ \(size,rate,h) -> do+ putStrLn $ "period size: " ++ show size+ putStrLn $ "sample rate: " ++ show rate+ mapM_ (write h) $+ SVL.chunks $+ SVL.map ((0.99*) . sin . ((2*pi * 440 / fromIntegral rate :: Float)*)) $+ SVL.iterate (SVL.chunkSize $ fromIntegral size) (1 +) 0
examples/synth.hs view
@@ -1,18 +1,19 @@-import qualified Sound.ALSA.PCM as PCM+import qualified Sound.ALSA.PCM.Node.ALSA as PCM+import qualified Sound.ALSA.PCM.Parameters.Software as SwParam+import qualified Sound.ALSA.PCM.Parameters.Hardware as HwParam -import qualified Sound.ALSA.PCM.Core as Core-import qualified Sound.ALSA.Exception as AlsaExc import qualified Sound.ALSA.PCM.Debug as Debug import qualified Sound.ALSA.Sequencer.Address as Addr import qualified Sound.ALSA.Sequencer.Client as Client import qualified Sound.ALSA.Sequencer.Port as Port-import qualified Sound.ALSA.Sequencer.Port.Info as PortInfo+import qualified Sound.ALSA.Sequencer.Port.InfoMonad as PortInfo import qualified Sound.ALSA.Sequencer.Event as Event import qualified Sound.ALSA.Sequencer.Queue as Queue+import qualified Sound.ALSA.Sequencer.Time as Time import qualified Sound.ALSA.Sequencer.RealTime as RealTime import qualified Sound.ALSA.Sequencer as SndSeq--- import qualified Sound.ALSA.Exception as AlsaExc+import Sound.ALSA.Sequencer.Event (Pitch, Velocity, ) import qualified Data.StorableVector.ST.Strict as SVST import qualified Data.StorableVector as SV@@ -26,87 +27,74 @@ import qualified Data.Map as Map -import Data.Word (Word8, )- import Control.Exception (bracket, ) import Control.Monad (liftM, forever, ) import Debug.Trace (trace, ) -soundFormat :: PCM.SoundFmt Float-soundFormat = PCM.SoundFmt { PCM.sampleFreq = 44100 }--openPCM :: IO (Int, Int, Core.Pcm)+openPCM ::+ (PCM.Access i, PCM.SampleFmt y) =>+ IO (PCM.Size, PCM.SampleFreq, PCM.Handle i y) openPCM = do Debug.put "alsaOpenTest"- h <- Core.pcm_open "default" Core.PcmStreamPlayback 0- (bufferTime,bufferSize,periodTime,periodSize,sampleRate) <-- setHwParams h- (PCM.withSampleFmt PCM.sampleFmtToPcmFormat soundFormat)- (PCM.numChannels soundFormat)- (PCM.sampleFreq soundFormat)- 1024 64- PCM.setSwParams h bufferSize periodSize- Core.pcm_prepare h+ (((bufferSize,periodSize),(bufferTime,periodTime),sampleRate), h) <-+ PCM.open (PCM.modes []) PCM.StreamPlayback+ (setHwParams 44100 1024 64)+ (\q@(sizes,_,_) -> do+ uncurry SwParam.setBufferSize sizes+ return q)+ "default"+ PCM.prepare h Debug.put $ "bufferTime = " ++ show bufferTime Debug.put $ "bufferSize = " ++ show bufferSize Debug.put $ "periodTime = " ++ show periodTime Debug.put $ "periodSize = " ++ show periodSize return (periodSize, sampleRate, h) -closePCM :: (Int, Int, Core.Pcm) -> IO ()-closePCM (_,_,pcm) = AlsaExc.rethrow $ do+closePCM :: (PCM.Size, PCM.SampleFreq, PCM.Handle i y) -> IO ()+closePCM (_,_,pcm) = do Debug.put "alsaClose"- Core.pcm_drain pcm- Core.pcm_close pcm+ PCM.drain pcm+ PCM.close pcm setHwParams ::- Core.Pcm- -> Core.PcmFormat- -> Int -- ^ number of channels- -> PCM.SampleFreq -- ^ sample frequency- -> Int -- ^ buffer size- -> Int -- ^ period size- -> IO (Int,Int,Int,Int,Int)- -- ^ (bufferTime,bufferSize,periodTime,periodSize)-setHwParams h format channels rate bufferSize periodSize =- PCM.withHwParams h $ \p -> do- Core.pcm_hw_params_set_access h p Core.PcmAccessRwInterleaved- Core.pcm_hw_params_set_format h p format- Core.pcm_hw_params_set_channels h p channels+ PCM.SampleFreq -- ^ sample frequency+ -> PCM.Size -- ^ buffer size+ -> PCM.Size -- ^ period size+ -> HwParam.T i y ((PCM.Size,PCM.Size),(PCM.Time,PCM.Time),PCM.SampleFreq)+ -- ^ ((bufferSize,periodSize),(bufferTime,periodTime),sampleRate)+setHwParams rate bufferSize periodSize = do {-- (actualRate,ord) <-- Core.pcm_hw_params_get_rate_max p- print ord+ (actualRate,ord) <- HwParam.getRateMax+ print ord -}- Core.pcm_hw_params_set_rate_resample h p False- (actualRate,_) <-- Core.pcm_hw_params_set_rate_near h p rate EQ- (actualPeriodSize,_) <-- Core.pcm_hw_params_set_period_size_near h p periodSize EQ- actualBufferSize <-- Core.pcm_hw_params_set_buffer_size_near h p- (max bufferSize (actualPeriodSize*2))+ HwParam.setRateResample False+ (actualRate,_) <-+ HwParam.setRateNear rate EQ+ (actualPeriodSize,_) <-+ HwParam.setPeriodSizeNear periodSize EQ+ actualBufferSize <-+ HwParam.setBufferSizeNear+ (max bufferSize (actualPeriodSize*2)) {-- let actualBufferSize = bufferSize- Core.pcm_hw_params_set_buffer_size h p bufferSize+ let actualBufferSize = bufferSize+ HwParam.setBufferSize bufferSize -}- (actualBufferTime,_) <- Core.pcm_hw_params_get_buffer_time p- (actualPeriodTime,_) <- Core.pcm_hw_params_get_period_time p- return (actualBufferTime, actualBufferSize,- actualPeriodTime, actualPeriodSize,- actualRate)+ (actualBufferTime,_) <- HwParam.getBufferTime+ (actualPeriodTime,_) <- HwParam.getPeriodTime+ return ((actualBufferSize, actualPeriodSize),+ (actualBufferTime, actualPeriodTime),+ actualRate) setTimestamping :: SndSeq.T mode -> Port.T -> Queue.T -> IO ()-setTimestamping h p q = do- info <- PortInfo.get h p- PortInfo.setTimestamping info True- PortInfo.setTimestampReal info True- PortInfo.setTimestampQueue info q- PortInfo.set h p info+setTimestamping h p q =+ PortInfo.modify h p $ do+ PortInfo.setTimestamping True+ PortInfo.setTimestampReal True+ PortInfo.setTimestampQueue q withInPort ::@@ -128,16 +116,17 @@ {- | RealTime.toFractional for NumericPrelude.--}+ realTimeToField :: (Fractional a) => RealTime.T -> a realTimeToField (RealTime.Cons s n) = fromIntegral s + fromIntegral n / (10^(9::Int))+-} addStamp :: Time -> Event.T -> StampedEvent addStamp rate ev =- (case Event.timestamp ev of- Event.RealTime t ->+ (case Event.time ev of+ Time.Cons Time.Absolute (Time.Real t) -> div (RealTime.toInteger t * rate) nano _ -> error "unsupported time stamp type", ev)@@ -186,7 +175,7 @@ (Addr.Cons c Port.unknown) (Event.CustomEv Event.Echo dat)) { Event.queue = q- , Event.timestamp = Event.RealTime t+ , Event.time = Time.consAbs $ Time.Real t , Event.dest = Addr.Cons { Addr.client = c, Addr.port = p@@ -211,8 +200,8 @@ _ -> False if abort then- case Event.timestamp ev of- Event.RealTime t -> do+ case Event.time ev of+ Time.Cons Time.Absolute (Time.Real _t) -> do -- putStrLn $ "got Echo at: " ++ show (RealTime.toInteger t :: Double) return [] _ -> error "unsupported time stamp type"@@ -245,19 +234,16 @@ arrange :: (Storable a, Num a) =>- Int ->+ PCM.Size -> [(Int, SV.Vector a)] -> SV.Vector a arrange size evs = SVST.runSTVector (do- v <- SVST.new size 0+ v <- SVST.new (fromIntegral size) 0 mapM_ (uncurry $ unsafeAddChunkToBuffer v) evs return v) -type Pitch = Word8-type Velocity = Word8- data OscillatorState a = OscillatorState a a Int {-@@ -298,13 +284,13 @@ amplitudeFromVelocity :: (Floating y) => Velocity -> y-amplitudeFromVelocity vel =+amplitudeFromVelocity (Event.Velocity vel) = 4 ** ((fromIntegral vel - 64) / 128) frequencyFromPitch :: (Floating y) => Pitch -> y-frequencyFromPitch pitch =+frequencyFromPitch (Event.Pitch pitch) = 440 * 2 ** (fromIntegral (fromIntegral pitch + 3 - 6*12 :: Int) / 12) normalizeNote :: Event.NoteEv -> Event.Note -> (Event.NoteEv, Velocity)@@ -313,14 +299,14 @@ velocity -> case notePart of Event.NoteOn ->- if velocity == 0- then (Event.NoteOff, 64)+ if velocity == Event.offVelocity+ then (Event.NoteOff, Event.normalVelocity) else (Event.NoteOn, velocity) _ -> (notePart, velocity) processEvents :: (Storable a, Floating a, Monad m) =>- Int ->+ PCM.Size -> PCM.SampleFreq -> [StampedEvent] -> MS.StateT (Time, Map.Map Pitch (OscillatorState a)) m [(Int, SV.Vector a)]@@ -332,7 +318,7 @@ let mplayingNew = fmap (\(start,s0) ->- case renderTone (size-start) s0 of+ case renderTone (fromIntegral size - start) s0 of (chunk, s1) -> ((start,chunk), s1)) mplaying in (fmap snd mplayingNew,@@ -383,10 +369,11 @@ write ::- (PCM.SampleFmt a) =>- Core.Pcm -> SV.Vector a -> IO ()+ (PCM.SampleFmt y) =>+ PCM.Handle PCM.Interleaved y -> SV.Vector y -> IO () write h xs =- SVB.withStartPtr xs $ PCM.alsaWrite h+ SVB.withStartPtr xs $ \buf ->+ fmap (const ()) . PCM.writeiRetry h buf . fromIntegral {-@@ -405,9 +392,9 @@ withInPort SndSeq.Block $ \sq port -> Queue.with sq $ \ q -> do setTimestamping sq port q- Queue.control sq q Event.QueueStart 0 Nothing+ Queue.control sq q Event.QueueStart Nothing _ <- Event.drainOutput sq- write h (SV.replicate (2*size) 0 :: SV.Vector Float)+ write h (SV.replicate (2 * fromIntegral size) 0 :: SV.Vector Float) flip MS.evalStateT (0,Map.empty) $ forever $ do startTime <- MS.gets fst let stopTime = startTime + fromIntegral size
examples/volume_meter.hs view
@@ -11,17 +11,17 @@ bufSize = 1000 inputFormat :: SoundFmt Int16-inputFormat = SoundFmt { sampleFreq = 8000 }+inputFormat = SoundFmt { sampleFreq = 8000 } main :: IO ()-main = let source = alsaSoundSource "plughw:0,0" inputFormat+main = let source = alsaSoundSource "default" inputFormat in allocaArray bufSize $ \buf -> withSoundSource source $ \from -> loop source from bufSize buf --- FIXME: assumes little-endian machine-loop :: SoundSource Int16 h -> h -> Int -> Ptr Int16 -> IO ()+-- | assumes that the file contains numbers in the host's byte order+loop :: SoundSource h Int16 -> h Int16 -> Int -> Ptr Int16 -> IO () loop src h n buf = do n' <- soundSourceRead src h (castPtr buf) n avg <- avgBuf buf n'
src/Sound/ALSA/PCM.hs view
@@ -1,13 +1,14 @@ {-# LANGUAGE ForeignFunctionInterface #-} module Sound.ALSA.PCM- (SampleFmt(..),+ (Class.SampleFmt(..), SampleFreq, Time,+ Size, SoundFmt(..), SoundSource(..), SoundSink(..), SoundBufferTime(..),- Pcm,+ Pcm, File, withSoundSource, withSoundSourceRunning, withSoundSink,@@ -22,159 +23,99 @@ alsaSoundSink, alsaSoundSourceTime, alsaSoundSinkTime,+ alsaSoundSourceParams,+ alsaSoundSinkParams, fileSoundSource, fileSoundSink, ) where -import Sound.ALSA.PCM.Core (Pcm)-import qualified Sound.ALSA.PCM.Core as PCM+import qualified Sound.ALSA.PCM.Node.ALSA as PCM+import qualified Sound.ALSA.PCM.Node.File as File++import Sound.ALSA.PCM.Parameters.Hardware (Time, SampleFreq, Size, )+import Sound.ALSA.PCM.Core.Handle (arraySize, )+import qualified Sound.ALSA.PCM.Parameters.Software as SwParam+import qualified Sound.ALSA.PCM.Parameters.Hardware as HwParam+import qualified Sound.ALSA.PCM.Core.Class as Class import qualified Sound.ALSA.Exception as AlsaExc import qualified Sound.ALSA.PCM.Debug as Debug import qualified Sound.Frame as Frame-import qualified Sound.Frame.Stereo as Stereo-import qualified Sound.Frame.MuLaw as MuLaw -import Data.Word (Word8, Word16, Word32, )-import Data.Int (Int8, Int16, Int32, )- import Control.Exception (bracket, bracket_, )-import Control.Monad (liftM, when, )-import Foreign.Marshal.Array (advancePtr, allocaArray, )-import Foreign.C (CSize, CInt, )-import Foreign (Storable, Ptr, minusPtr, )+import Control.Monad (when, liftM2, liftM4, )++import qualified Foreign.C.Types as C+import Foreign.Marshal.Array (allocaArray, )+import Foreign.Ptr (Ptr, )+import Foreign.Storable (Storable, ) import qualified System.IO as IO-import System.IO- (IOMode(ReadMode, WriteMode), Handle, openBinaryFile, hClose, ) -- -- * Generic sound API -- -class (Storable y, Frame.C y) => SampleFmt y where- sampleFmtToPcmFormat :: y -> PCM.Format--type SampleFreq = Int- data SoundFmt y = SoundFmt { sampleFreq :: SampleFreq } deriving (Show) -type Time = Int- data SoundBufferTime = SoundBufferTime { bufferTime, periodTime :: Time } deriving (Show) --- | Counts are in samples, not bytes. Multi-channel data is interleaved.-data SoundSource y handle =- SoundSource {- soundSourceFmt :: SoundFmt y,- soundSourceOpen :: IO handle,- soundSourceClose :: handle -> IO (),- soundSourceStart :: handle -> IO (),- soundSourceStop :: handle -> IO (),- soundSourceRead :: handle -> Ptr y -> Int -> IO Int- }+type Pcm = PCM.Handle PCM.Interleaved -data SoundSink y handle =- SoundSink {- soundSinkFmt :: SoundFmt y,- soundSinkOpen :: IO handle,- soundSinkClose :: handle -> IO (),- soundSinkWrite :: handle -> Ptr y -> Int -> IO (),- soundSinkStart :: handle -> IO (),- soundSinkStop :: handle -> IO ()- }+type File = File.Handle --------- -defaultBufferTime :: SoundBufferTime-defaultBufferTime =- SoundBufferTime {- bufferTime = 500000, -- 0.5s- periodTime = 100000 -- 0.1s- }--nullSoundSource :: SoundFmt y -> SoundSource y h-nullSoundSource fmt =- SoundSource {- soundSourceFmt = fmt,- soundSourceOpen = return undefined,- soundSourceClose = \_ -> return (),- soundSourceStart = \_ -> return (),- soundSourceStop = \_ -> return (),- soundSourceRead = \_ _ _ -> return 0- }+-- | Counts are in samples, not bytes. Multi-channel data is interleaved.+data SoundSource handle y =+ SoundSource {+ soundSourceOpen :: IO (handle y),+ soundSourceClose :: handle y -> IO (),+ soundSourceStart :: handle y -> IO (),+ soundSourceStop :: handle y -> IO (),+ soundSourceRead :: handle y -> Ptr y -> Size -> IO Size+ } -nullSoundSink :: SoundFmt y -> SoundSink y h-nullSoundSink fmt =- SoundSink {- soundSinkFmt = fmt,- soundSinkOpen = return undefined,- soundSinkClose = \_ -> return (),- soundSinkStart = \_ -> return (),- soundSinkStop = \_ -> return (),- soundSinkWrite = \_ _ _ -> return ()- }+data SoundSink handle y =+ SoundSink {+ soundSinkOpen :: IO (handle y),+ soundSinkClose :: handle y -> IO (),+ soundSinkWrite :: handle y -> Ptr y -> Size -> IO (),+ soundSinkStart :: handle y -> IO (),+ soundSinkStop :: handle y -> IO ()+ } -withSoundSource :: SoundSource y h -> (h -> IO a) -> IO a+withSoundSource :: SoundSource handle y -> (handle y -> IO a) -> IO a withSoundSource source = bracket (soundSourceOpen source) (soundSourceClose source) -withSoundSourceRunning :: SoundSource y h -> h -> IO a -> IO a-withSoundSourceRunning src h = bracket_ (soundSourceStart src h) (soundSourceStop src h)+withSoundSourceRunning :: SoundSource handle y -> handle y -> IO a -> IO a+withSoundSourceRunning src h =+ bracket_ (soundSourceStart src h) (soundSourceStop src h) -withSoundSink :: SoundSink y h -> (h -> IO a) -> IO a+withSoundSink :: SoundSink handle y -> (handle y -> IO a) -> IO a withSoundSink sink = bracket (soundSinkOpen sink) (soundSinkClose sink) -withSoundSinkRunning :: SoundSink y h -> h -> IO a -> IO a-withSoundSinkRunning src h = bracket_ (soundSinkStart src h) (soundSinkStop src h)+withSoundSinkRunning :: SoundSink handle y -> handle y -> IO a -> IO a+withSoundSinkRunning src h =+ bracket_ (soundSinkStart src h) (soundSinkStop src h) -instance SampleFmt Word8 where- sampleFmtToPcmFormat _ = PCM.FormatU8--instance SampleFmt Int8 where- sampleFmtToPcmFormat _ = PCM.FormatS8--instance SampleFmt Word16 where- sampleFmtToPcmFormat _ = PCM.FormatU16--instance SampleFmt Int16 where- sampleFmtToPcmFormat _ = PCM.FormatS16--instance SampleFmt Word32 where- sampleFmtToPcmFormat _ = PCM.FormatU32--instance SampleFmt Int32 where- sampleFmtToPcmFormat _ = PCM.FormatS32--instance SampleFmt Float where- sampleFmtToPcmFormat _ = PCM.FormatFloat--instance SampleFmt Double where- sampleFmtToPcmFormat _ = PCM.FormatFloat64--instance SampleFmt MuLaw.T where- sampleFmtToPcmFormat _ = PCM.FormatMuLaw--instance SampleFmt a => SampleFmt (Stereo.T a) where- sampleFmtToPcmFormat y =- sampleFmtToPcmFormat (Stereo.left y)- withSampleFmt :: (y -> a) -> (SoundFmt y -> a) withSampleFmt f _ = f undefined +withNodeSample :: (y -> a) -> (node y -> a)+withNodeSample f _ = f undefined -soundFmtMIME :: SampleFmt y => SoundFmt y -> String++soundFmtMIME :: Class.SampleFmt y => SoundFmt y -> String soundFmtMIME fmt = t ++ r ++ c where t = "audio/basic" {-@@ -183,13 +124,15 @@ SampleFmtMuLaw8Bit -> "audio/basic" -} r = ";rate=" ++ show (sampleFreq fmt)- c | numChannels fmt == 1 = ""- | otherwise = ";channels=" ++ show (numChannels fmt)+ c =+ if numChannels fmt == 1+ then ""+ else ";channels=" ++ show (numChannels fmt) -numChannels :: SampleFmt y => SoundFmt y -> Int+numChannels :: Class.SampleFmt y => SoundFmt y -> Int numChannels = withSampleFmt Frame.numberOfChannels -audioBytesPerSample :: SampleFmt y => SoundFmt y -> Int+audioBytesPerSample :: Class.SampleFmt y => SoundFmt y -> Int audioBytesPerSample = withSampleFmt Frame.sizeOfElement {-@@ -199,22 +142,25 @@ a frame might occupy more than the calculated size in an array in memory. -}-audioBytesPerFrame :: SampleFmt y => SoundFmt y -> Int+audioBytesPerFrame :: Class.SampleFmt y => SoundFmt y -> Int audioBytesPerFrame fmt = numChannels fmt * audioBytesPerSample fmt -soundSourceBytesPerFrame :: SampleFmt y => SoundSource y h -> Int-soundSourceBytesPerFrame = audioBytesPerFrame . soundSourceFmt+soundSourceBytesPerFrame :: Class.SampleFmt y => SoundSource handle y -> Int+soundSourceBytesPerFrame =+ withNodeSample $ \y -> Frame.numberOfChannels y * Frame.sizeOfElement y -soundSinkBytesPerFrame :: SampleFmt y => SoundSink y h -> Int-soundSinkBytesPerFrame = audioBytesPerFrame . soundSinkFmt+soundSinkBytesPerFrame :: Class.SampleFmt y => SoundSink handle y -> Int+soundSinkBytesPerFrame =+ withNodeSample $ \y -> Frame.numberOfChannels y * Frame.sizeOfElement y -copySound :: SampleFmt y =>- SoundSource y h1- -> SoundSink y h2- -> Int -- ^ Buffer size (in sample frames) to use- -> IO ()+copySound ::+ Class.SampleFmt y =>+ SoundSource handleIn y+ -> SoundSink handleOut y+ -> Size -- ^ Buffer size (in sample frames) to use+ -> IO () copySound source sink bufSize =- allocaArray bufSize $ \buf ->+ allocaArray (fromIntegral bufSize) $ \buf -> withSoundSource source $ \from -> withSoundSink sink $ \to -> let loop = do n <- soundSourceRead source from buf bufSize@@ -227,250 +173,192 @@ -- -alsaOpen :: SampleFmt y =>- String -- ^ device, e.g @"default"@- -> SoundFmt y- -> SoundBufferTime- -> PCM.Stream- -> IO Pcm-alsaOpen dev fmt time stream = AlsaExc.rethrow $- do Debug.put "alsaOpen"- h <- PCM.open dev stream 0- Debug.put $ "requested buffer_time = " ++ show (bufferTime time)- Debug.put $ "requested period_time = " ++ show (periodTime time)- (buffer_time,buffer_size,period_time,period_size) <-- setHwParams h (withSampleFmt sampleFmtToPcmFormat fmt)- (numChannels fmt)- (sampleFreq fmt)- (bufferTime time)- (periodTime time)- setSwParams h buffer_size period_size- PCM.prepare h- Debug.put $ "buffer_time = " ++ show buffer_time- Debug.put $ "buffer_size = " ++ show buffer_size- Debug.put $ "period_time = " ++ show period_time- Debug.put $ "period_size = " ++ show period_size- when (stream == PCM.StreamPlayback) $- callocaArray fmt period_size $ \buf ->- PCM.writei h buf period_size >> return ()- return h+{- |+The buffer is initialized with an empty block+which means that the zero bit pattern+should equal the number zero in the Class.SampleFmt type.+-}+alsaOpen :: Class.SampleFmt y =>+ PCM.Stream ->+ HwParam.T PCM.Interleaved y a ->+ (a -> SwParam.T PCM.Interleaved y ()) ->+ String {- ^ device, e.g @"default"@ -} ->+ IO (Pcm y)+alsaOpen stream hwParams swParams dev = AlsaExc.rethrow $ do+ Debug.put "alsaOpen"+ {-+ Debug.put $ "requested bufferTime = " ++ show (bufferTime time)+ Debug.put $ "requested periodTime = " ++ show (periodTime time)+ -}+ ((bufferTime_,bufferSize_,periodTime_,periodSize_), h) <-+ PCM.open (PCM.modes []) stream+ (liftM2 (,) hwParams $+ liftM4 (,,,)+ HwParam.getBufferSize+ HwParam.getBufferTime+ (fmap fst HwParam.getPeriodSize)+ (fmap fst HwParam.getPeriodTime))+ (\(a, params) -> swParams a >> return params)+ dev+ PCM.prepare h+ Debug.put $ "bufferTime = " ++ show bufferTime_+ Debug.put $ "bufferSize = " ++ show bufferSize_+ Debug.put $ "periodTime = " ++ show periodTime_+ Debug.put $ "periodSize = " ++ show periodSize_+ when (stream == PCM.StreamPlayback) $+ callocaArray periodSize_ $ \buf ->+ PCM.writei h buf (fromIntegral periodSize_) >> return ()+ return h +alsaClose :: Pcm y -> IO ()+alsaClose h = AlsaExc.rethrow $ do+ Debug.put "alsaClose"+ PCM.drain h+ PCM.close h -setHwParams :: Pcm- -> PCM.Format- -> Int -- ^ number of channels- -> SampleFreq -- ^ sample frequency- -> Time -- ^ buffer time- -> Time -- ^ period time- -> IO (Int,Int,Int,Int)- -- ^ (buffer_time,buffer_size,period_time,period_size)-setHwParams h format channels rate buffer_time period_time- = withHwParams h $ \p ->- do PCM.hw_params_set_access h p PCM.AccessRwInterleaved- PCM.hw_params_set_format h p format- PCM.hw_params_set_channels h p channels- PCM.hw_params_set_rate h p rate EQ- (actual_buffer_time,_) <-- PCM.hw_params_set_buffer_time_near h p buffer_time EQ- buffer_size <- PCM.hw_params_get_buffer_size p- (actual_period_time,_) <-- PCM.hw_params_set_period_time_near h p period_time EQ- (period_size,_) <- PCM.hw_params_get_period_size p- return (actual_buffer_time,buffer_size,- actual_period_time,period_size) -setSwParams :: Pcm- -> Int -- ^ buffer size- -> Int -- ^ period size- -> IO ()-setSwParams h _buffer_size period_size = withSwParams h $ \p ->- do -- let start_threshold =- -- (buffer_size `div` period_size) * period_size- --PCM.sw_params_set_start_threshold h p start_threshold- PCM.sw_params_set_start_threshold h p 0- PCM.sw_params_set_avail_min h p period_size- PCM.sw_params_set_xfer_align h p 1- -- pad buffer with silence when needed- --PCM.sw_params_set_silence_size h p period_size- --PCM.sw_params_set_silence_threshold h p period_size--withHwParams :: Pcm -> (PCM.HwParams -> IO a) -> IO a-withHwParams h f =- bracket PCM.hw_params_malloc PCM.hw_params_free $ \p ->- do PCM.hw_params_any h p- x <- f p- PCM.hw_params h p- return x--withSwParams :: Pcm -> (PCM.SwParams -> IO a) -> IO a-withSwParams h f =- bracket PCM.sw_params_malloc PCM.sw_params_free $ \p ->- do PCM.sw_params_current h p- x <- f p- PCM.sw_params h p- return x--alsaClose :: Pcm -> IO ()-alsaClose pcm = AlsaExc.rethrow $- do Debug.put "alsaClose"- PCM.drain pcm- PCM.close pcm--alsaStart :: Pcm -> IO ()-alsaStart pcm = AlsaExc.rethrow $- do Debug.put "alsaStart"- PCM.prepare pcm- PCM.start pcm-+alsaStart :: Pcm y -> IO ()+alsaStart h = AlsaExc.rethrow $ do+ Debug.put "alsaStart"+ PCM.prepare h+ PCM.start h -- FIXME: use PCM.drain for sinks?-alsaStop :: Pcm -> IO ()-alsaStop pcm = AlsaExc.rethrow $- do Debug.put "alsaStop"- PCM.drain pcm+alsaStop :: Pcm y -> IO ()+alsaStop h = AlsaExc.rethrow $ do+ Debug.put "alsaStop"+ PCM.drain h + alsaRead ::- SampleFmt y =>- Pcm -> Ptr y -> Int -> IO Int+ Class.SampleFmt y =>+ Pcm y -> Ptr y -> Size -> IO Size alsaRead h buf0 n =- let go buf offset = do- -- debug $ "Reading " ++ show n ++ " samples..."- nread <-- PCM.readi h buf (n-offset)- `AlsaExc.catchXRun`- do Debug.put "snd_pcm_readi reported buffer over-run"- PCM.prepare h- go buf offset- let newOffset = offset+nread- -- debug $ "Got " ++ show n' ++ " samples."- if newOffset < n- then go (advancePtr buf nread) newOffset- else return newOffset- in AlsaExc.rethrow $ go buf0 0-+ AlsaExc.rethrow $ PCM.readiRetry h buf0 n alsaWrite ::- SampleFmt y =>- Pcm -> Ptr y -> Int -> IO ()-alsaWrite h buf n = AlsaExc.rethrow $- alsaWrite_ h buf n >> return ()+ Class.SampleFmt y =>+ Pcm y -> Ptr y -> Size -> IO Size+alsaWrite h buf0 n =+ AlsaExc.rethrow $ PCM.writeiRetry h buf0 n -alsaWrite_ ::- SampleFmt y =>- Pcm -> Ptr y -> Int -> IO Int-alsaWrite_ h buf0 n =- let go buf offset = do- --debug $ "Writing " ++ show n ++ " samples..."- nwritten <-- PCM.writei h buf n- `AlsaExc.catchXRun`- do Debug.put "snd_pcm_writei reported buffer under-run"- PCM.prepare h- go buf offset- let newOffset = offset+nwritten- --debug $ "Wrote " ++ show n' ++ " samples."- if newOffset < n- then go (advancePtr buf nwritten) newOffset- else return newOffset- in AlsaExc.rethrow $ go buf0 0 +defaultBufferTime :: SoundBufferTime+defaultBufferTime =+ SoundBufferTime {+ bufferTime = 500000, -- 0.5s+ periodTime = 100000 -- 0.1s+ } +bufferTimeParams ::+ SoundFmt y ->+ SoundBufferTime ->+ (HwParam.T PCM.Interleaved y (Size,Size),+ (Size,Size) -> SwParam.T PCM.Interleaved y ())+bufferTimeParams fmt time =+ (HwParam.setRateBufferTime+ (sampleFreq fmt)+ (bufferTime time)+ (periodTime time),+ uncurry SwParam.setBufferSize)+ alsaSoundSource ::- SampleFmt y =>- String -> SoundFmt y -> SoundSource y Pcm+ Class.SampleFmt y =>+ String -> SoundFmt y -> SoundSource Pcm y alsaSoundSource dev fmt = alsaSoundSourceTime dev fmt defaultBufferTime alsaSoundSink ::- SampleFmt y =>- String -> SoundFmt y -> SoundSink y Pcm+ Class.SampleFmt y =>+ String -> SoundFmt y -> SoundSink Pcm y alsaSoundSink dev fmt = alsaSoundSinkTime dev fmt defaultBufferTime alsaSoundSourceTime ::- SampleFmt y =>- String -> SoundFmt y -> SoundBufferTime -> SoundSource y Pcm+ Class.SampleFmt y =>+ String -> SoundFmt y -> SoundBufferTime -> SoundSource Pcm y alsaSoundSourceTime dev fmt time =- (nullSoundSource fmt) {- soundSourceOpen = alsaOpen dev fmt time PCM.StreamCapture,- soundSourceClose = alsaClose,- soundSourceStart = alsaStart,- soundSourceStop = alsaStop,- soundSourceRead = alsaRead- }+ uncurry (alsaSoundSourceParams dev) $+ bufferTimeParams fmt time alsaSoundSinkTime ::- SampleFmt y =>- String -> SoundFmt y -> SoundBufferTime -> SoundSink y Pcm+ Class.SampleFmt y =>+ String -> SoundFmt y -> SoundBufferTime -> SoundSink Pcm y alsaSoundSinkTime dev fmt time =- (nullSoundSink fmt) {- soundSinkOpen = alsaOpen dev fmt time PCM.StreamPlayback,- soundSinkClose = alsaClose,- soundSinkStart = alsaStart,- soundSinkStop = alsaStop,- soundSinkWrite = alsaWrite- }+ uncurry (alsaSoundSinkParams dev) $+ bufferTimeParams fmt time +alsaSoundSourceParams ::+ Class.SampleFmt y =>+ String ->+ HwParam.T PCM.Interleaved y a ->+ (a -> SwParam.T PCM.Interleaved y ()) ->+ SoundSource Pcm y+alsaSoundSourceParams dev hwParams swParams =+ SoundSource {+ soundSourceOpen = alsaOpen PCM.StreamCapture hwParams swParams dev,+ soundSourceClose = alsaClose,+ soundSourceStart = alsaStart,+ soundSourceStop = alsaStop,+ soundSourceRead = alsaRead+ }++alsaSoundSinkParams ::+ Class.SampleFmt y =>+ String ->+ HwParam.T PCM.Interleaved y a ->+ (a -> SwParam.T PCM.Interleaved y ()) ->+ SoundSink Pcm y+alsaSoundSinkParams dev hwParams swParams =+ SoundSink {+ soundSinkOpen = alsaOpen PCM.StreamPlayback hwParams swParams dev,+ soundSinkClose = alsaClose,+ soundSinkStart = alsaStart,+ soundSinkStop = alsaStop,+ soundSinkWrite = \h buf n -> alsaWrite h buf n >> return ()+ }+ -- -- * File stuff -- -{- |-This expects pad bytes that are needed in memory-in order to satisfy aligment constraints.-This is only a problem for samples sizes like 24 bit.--}-fileRead ::- SampleFmt y =>- Handle -> Ptr y -> Int -> IO Int-fileRead h buf n =- liftM (`div` arraySize buf 1) $- IO.hGetBuf h buf (arraySize buf n)--{- |-Same restrictions as for 'fileRead'.--}-fileWrite ::- SampleFmt y =>- Handle -> Ptr y -> Int -> IO ()-fileWrite h buf n =- IO.hPutBuf h buf (arraySize buf n)- fileSoundSource ::- SampleFmt y =>- FilePath -> SoundFmt y -> SoundSource y Handle-fileSoundSource file fmt =- (nullSoundSource fmt) {- soundSourceOpen = openBinaryFile file ReadMode,- soundSourceClose = hClose,- soundSourceRead = fileRead- }+ Class.SampleFmt y =>+ FilePath -> SoundSource File y+fileSoundSource file =+ SoundSource {+ soundSourceOpen = File.open IO.ReadMode file,+ soundSourceClose = File.close,+ soundSourceRead = File.read,+ soundSourceStart = const $ return (),+ soundSourceStop = const $ return ()+ } fileSoundSink ::- SampleFmt y =>- FilePath -> SoundFmt y -> SoundSink y Handle-fileSoundSink file fmt =- (nullSoundSink fmt) {- soundSinkOpen = openBinaryFile file WriteMode,- soundSinkClose = hClose,- soundSinkWrite = fileWrite- }+ Class.SampleFmt y =>+ FilePath -> SoundSink File y+fileSoundSink file =+ SoundSink {+ soundSinkOpen = File.open IO.WriteMode file,+ soundSinkClose = File.close,+ soundSinkWrite = File.write,+ soundSinkStart = const $ return (),+ soundSinkStop = const $ return ()+ } -- -- * Marshalling utilities -- -callocaArray :: Storable y => SoundFmt y -> Int -> (Ptr y -> IO b) -> IO b-callocaArray _ n f =- allocaArray n $ \p ->- clearBytes p (arraySize p n) >>- f p+callocaArray :: Storable y => Size -> (Ptr y -> IO b) -> IO b+callocaArray n0 f =+ case fromIntegral n0 of+ n ->+ allocaArray n $ \p ->+ clearBytes p (arraySize p n) >>+ f p clearBytes :: Ptr a -> Int -> IO () clearBytes p n = memset p 0 (fromIntegral n) >> return () -{-# INLINE arraySize #-}-arraySize :: Storable y => Ptr y -> Int -> Int-arraySize p n = advancePtr p n `minusPtr` p--foreign import ccall unsafe "string.h" memset :: Ptr a -> CInt -> CSize -> IO (Ptr a)+foreign import ccall unsafe "string.h" memset :: Ptr a -> C.CInt -> C.CSize -> IO (Ptr a)
− src/Sound/ALSA/PCM/C2HS.hs
@@ -1,237 +0,0 @@--- C->Haskell Compiler: Marshalling library------ Copyright (c) [1999...2005] Manuel M T Chakravarty------ Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are met:------ 1. Redistributions of source code must retain the above copyright notice,--- this list of conditions and the following disclaimer.--- 2. Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- 3. The name of the author may not be used to endorse or promote products--- derived from this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR--- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES--- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN--- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,--- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED--- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.------- Description --------------------------------------------------------------------- Language: Haskell 98------ This module provides the marshaling routines for Haskell files produced by--- C->Haskell for binding to C library interfaces. It exports all of the--- low-level FFI (language-independent plus the C-specific parts) together--- with the C->HS-specific higher-level marshalling routines.-----module Sound.ALSA.PCM.C2HS (-- -- * Re-export the language-independent component of the FFI- St.Storable, St.poke, St.peek, St.sizeOf, St.alignment,- Ptr, castPtr, with,- Alloc.alloca,-- -- * Re-export the C language component of the FFI- C.CInt, C.CUInt, C.CLong, C.CULong, C.CChar, C.withCString,-- -- * Composite marshalling functions- withCStringLenIntConv, peekCStringLenIntConv, withIntConv, withFloatConv,- peekIntConv, peekFloatConv, withBool, peekBool, withEnum, peekEnum,-- -- * Conditional results using 'Maybe'- nothingIf, nothingIfNull,-- -- * Bit masks- combineBitMasks, containsBitMask, extractBitMasks,-- -- * Conversion between C and Haskell types- cIntConv, cFloatConv, cToBool, cFromBool, cToEnum, cFromEnum-) where---import Foreign.Ptr (Ptr, nullPtr, castPtr, )-import Foreign.Storable (Storable, peek, )-import Foreign.Marshal.Utils (fromBool, toBool, with, )--import qualified Foreign.Storable as St-import qualified Foreign.Marshal.Alloc as Alloc-import qualified Foreign.C as C--import Data.Bits (Bits, (.|.), (.&.), )--import Control.Monad (liftM, )----- Composite marshalling functions--- ----------------------------------- Strings with explicit length----withCStringLenIntConv ::- (Integral i) =>- String -> ((Ptr C.CChar, i) -> IO a) -> IO a-withCStringLenIntConv s f =- C.withCStringLen s $ \(p, n) -> f (p, cIntConv n)--peekCStringLenIntConv ::- (Integral i) =>- (Ptr C.CChar, i) -> IO String-peekCStringLenIntConv (s, n) =- C.peekCStringLen (s, cIntConv n)----- Marshalling of numerals-----withIntConv :: (Storable b, Integral a, Integral b)- => a -> (Ptr b -> IO c) -> IO c-withIntConv = with . cIntConv--withFloatConv :: (Storable b, RealFloat a, RealFloat b)- => a -> (Ptr b -> IO c) -> IO c-withFloatConv = with . cFloatConv--peekIntConv :: (Storable a, Integral a, Integral b)- => Ptr a -> IO b-peekIntConv = liftM cIntConv . peek--peekFloatConv :: (Storable a, RealFloat a, RealFloat b)- => Ptr a -> IO b-peekFloatConv = liftM cFloatConv . peek---- Passing Booleans by reference-----withBool :: (Integral a, Storable a) => Bool -> (Ptr a -> IO b) -> IO b-withBool = with . fromBool--peekBool :: (Integral a, Storable a) => Ptr a -> IO Bool-peekBool = liftM toBool . peek----- Passing enums by reference-----withEnum :: (Enum a, Integral b, Storable b) => a -> (Ptr b -> IO c) -> IO c-withEnum = with . cFromEnum--peekEnum :: (Enum a, Integral b, Storable b) => Ptr b -> IO a-peekEnum = liftM cToEnum . peek----- Storing of 'Maybe' values--- ---------------------------{--instance Storable a => Storable (Maybe a) where- sizeOf _ = sizeOf (undefined :: Ptr ())- alignment _ = alignment (undefined :: Ptr ())-- peek p = do- ptr <- peek (castPtr p)- if ptr == nullPtr- then return Nothing- else liftM Just $ peek ptr-- poke p v = do- ptr <- case v of- Nothing -> return nullPtr- Just v' -> new v'- poke (castPtr p) ptr--}---- Conditional results using 'Maybe'--- ------------------------------------- Wrap the result into a 'Maybe' type.------ * the predicate determines when the result is considered to be non-existing,--- ie, it is represented by `Nothing'------ * the second argument allows to map a result wrapped into `Just' to some--- other domain----nothingIf :: (a -> Bool) -> (a -> b) -> a -> Maybe b-nothingIf p f x = if p x then Nothing else Just $ f x---- |Instance for special casing null pointers.----nothingIfNull :: (Ptr a -> b) -> Ptr a -> Maybe b-nothingIfNull = nothingIf (== nullPtr)----- Support for bit masks--- ------------------------- Given a list of enumeration values that represent bit masks, combine these--- masks using bitwise disjunction.----combineBitMasks :: (Enum a, Bits b) => [a] -> b-combineBitMasks = foldl (.|.) 0 . map (fromIntegral . fromEnum)---- Tests whether the given bit mask is contained in the given bit pattern--- (i.e., all bits set in the mask are also set in the pattern).----containsBitMask :: (Bits a, Enum b) => a -> b -> Bool-bits `containsBitMask` bm = let bm' = fromIntegral . fromEnum $ bm- in- bm' .&. bits == bm'---- |Given a bit pattern, yield all bit masks that it contains.------ * This does *not* attempt to compute a minimal set of bit masks that when--- combined yield the bit pattern, instead all contained bit masks are--- produced.----extractBitMasks :: (Bits a, Enum b, Bounded b) => a -> [b]-extractBitMasks bits =- [bm | bm <- [minBound..maxBound], bits `containsBitMask` bm]----- Conversion routines--- ----------------------- |Integral conversion----cIntConv :: (Integral a, Integral b) => a -> b-cIntConv = fromIntegral---- |Floating conversion----cFloatConv :: (RealFloat a, RealFloat b) => a -> b-cFloatConv = realToFrac--- As this conversion by default goes via `Rational', it can be very slow...-{-# RULES- "cFloatConv/Float->Float" forall (x::Float). cFloatConv x = x;- "cFloatConv/Double->Double" forall (x::Double). cFloatConv x = x- #-}---- |Obtain C value from Haskell 'Bool'.----cFromBool :: Num a => Bool -> a-cFromBool = fromBool---- |Obtain Haskell 'Bool' from C value.----cToBool :: Num a => a -> Bool-cToBool = toBool---- |Convert a C enumeration to Haskell.----cToEnum :: (Integral i, Enum e) => i -> e-cToEnum = toEnum . cIntConv---- |Convert a Haskell enumeration to C.----cFromEnum :: (Enum e, Integral i) => e -> i-cFromEnum = cIntConv . fromEnum
− src/Sound/ALSA/PCM/Core.chs
@@ -1,316 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}-module Sound.ALSA.PCM.Core where--import Sound.ALSA.PCM.C2HS (cIntConv, peekIntConv, withIntConv, cFromEnum, )-import Sound.ALSA.Exception (checkResult, checkResult_, )--import Foreign.C.Types (CUInt, CULong, CInt, CLong, CChar, )-import Foreign.C.String (withCString, )-import Foreign.Ptr (Ptr, castPtr, )-import Foreign.Storable (Storable, sizeOf, alignment, peek, poke, )-import Foreign.Marshal.Utils (with, )-import Foreign.Marshal.Alloc (alloca, )------ HACK for 32-bit machines.--- This is only used to be able to parse alsa/pcm.h,--- since snd_pcm_format_silence_64 use u_int64_t which is not--- defined on 32-bit machines, AFAICT-#if __WORDSIZE == 32-typedef unsigned long long int u_int64_t;-#endif--#include <alsa/asoundlib.h>--{#context prefix = "snd_pcm_"#}--{#pointer *snd_pcm_t as Pcm newtype #}--instance Storable Pcm where- sizeOf (Pcm r) = sizeOf r- alignment (Pcm r) = alignment r- peek p = fmap Pcm (peek (castPtr p))- poke p (Pcm r) = poke (castPtr p) r--{#pointer *snd_pcm_hw_params_t as HwParams newtype #}--instance Storable HwParams where- sizeOf (HwParams r) = sizeOf r- alignment (HwParams r) = alignment r- peek p = fmap HwParams (peek (castPtr p))- poke p (HwParams r) = poke (castPtr p) r--{#pointer *snd_pcm_sw_params_t as SwParams newtype #}--instance Storable SwParams where- sizeOf (SwParams r) = sizeOf r- alignment (SwParams r) = alignment r- peek p = fmap SwParams (peek (castPtr p))- poke p (SwParams r) = poke (castPtr p) r--{#enum _snd_pcm_stream as Stream {underscoreToCase} deriving (Eq,Show)#}--{#enum _snd_pcm_access as Access {underscoreToCase} deriving (Eq,Show)#}--{#enum _snd_pcm_format as Format {underscoreToCase} deriving (Eq,Show)#}--{#fun snd_pcm_open as open- { alloca- `Pcm' peek*,- withCString* `String',- cFromEnum `Stream',- `Int'}- -> `()' result*- #}- where result = checkResult_ "PCM.open"--{#fun snd_pcm_close as close- { id `Pcm' }- -> `()' result*- #}- where result = checkResult_ "PCM.close"--{#fun prepare- { id `Pcm' }- -> `()' result*- #}- where result = checkResult_ "PCM.prepare"--{#fun start- { id `Pcm' }- -> `()' result*- #}- where result = checkResult_ "PCM.start"--{#fun drop- { id `Pcm' }- -> `()' result*- #}- where result = checkResult_ "PCM.drop"--{#fun drain- { id `Pcm' }- -> `()' result*- #}- where result = checkResult_ "PCM.drain"--{---- Only available in 1.0.11rc3 and later-{#fun set_params- { id `Pcm',- cFromEnum `PcmFormat',- cFromEnum `PcmAccess',- `Int',- `Int',- `Bool',- `Int' }- -> `()' result*- #}- where result = checkResult_ "PCM.set_params"--}--{#fun hw_params- { id `Pcm',- id `HwParams' }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params"--{#fun hw_params_any- { id `Pcm',- id `HwParams' }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_any"--{#fun hw_params_set_access- { id `Pcm',- id `HwParams',- cFromEnum `Access'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_access"--{#fun hw_params_set_format- { id `Pcm',- id `HwParams',- cFromEnum `Format'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_format"--{#fun hw_params_set_rate- { id `Pcm',- id `HwParams',- `Int',- orderingToInt `Ordering'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_rate"--{---- Available in 1.0.9rc2 and later-{#fun hw_params_set_rate_resample- { id `Pcm',- id `HwParams',- `Bool'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_rate_resample"--}--{#fun hw_params_set_channels- { id `Pcm',- id `HwParams',- `Int'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_channels"--{#fun hw_params_set_buffer_size- { id `Pcm',- id `HwParams',- `Int'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_buffer_size"--{#fun hw_params_get_buffer_size- { id `HwParams',- alloca- `Int' peekIntConv*- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_get_buffer_size"--{#fun hw_params_get_period_size- { id `HwParams',- alloca- `Int' peekIntConv*,- alloca- `Ordering' peekOrdering*- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_get_period_size"--{#fun hw_params_set_period_time_near- { id `Pcm',- id `HwParams',- withIntConv* `Int' peekIntConv*,- withOrdering* `Ordering' peekOrdering*- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_period_time_near"--{#fun hw_params_set_periods- { id `Pcm',- id `HwParams',- `Int',- orderingToInt `Ordering'- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_periods"--{#fun hw_params_set_buffer_time_near- { id `Pcm',- id `HwParams',- withIntConv* `Int' peekIntConv*,- withOrdering* `Ordering' peekOrdering*- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_set_buffer_time_near"--{#fun hw_params_get_buffer_time- { id `HwParams',- alloca- `Int' peekIntConv*,- alloca- `Ordering' peekOrdering*- }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_get_buffer_time"--{#fun sw_params_set_start_threshold- { id `Pcm',- id `SwParams',- `Int'- }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_set_start_threshold"--{#fun sw_params_set_avail_min- { id `Pcm',- id `SwParams',- `Int'- }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_set_avail_min"--{#fun sw_params_set_xfer_align- { id `Pcm',- id `SwParams',- `Int' }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_set_xfer_align"--{#fun sw_params_set_silence_threshold- { id `Pcm',- id `SwParams',- `Int' }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_set_silence_threshold"--{#fun sw_params_set_silence_size- { id `Pcm',- id `SwParams',- `Int' }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_set_silence_size"--{#fun readi- { id `Pcm',- castPtr `Ptr a',- `Int'- }- -> `Int' result* #}- where result = fmap fromIntegral . checkResult "PCM.readi"--{#fun writei- { id `Pcm',- castPtr `Ptr a',- `Int'- }- -> `Int' result* #}- where result = fmap fromIntegral . checkResult "PCM.writei"--{#fun hw_params_malloc- { alloca- `HwParams' peek* }- -> `()' result*- #}- where result = checkResult_ "PCM.hw_params_malloc"--{#fun hw_params_free- { id `HwParams' }- -> `()' #}--{#fun sw_params_malloc- { alloca- `SwParams' peek* }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_malloc"--{#fun sw_params_free- { id `SwParams' }- -> `()' #}--{#fun sw_params- { id `Pcm',- id `SwParams' }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params"--{#fun sw_params_current- { id `Pcm',- id `SwParams' }- -> `()' result*- #}- where result = checkResult_ "PCM.sw_params_current"------- * Marshalling utilities-----orderingToInt :: Ordering -> CInt-orderingToInt o = fromIntegral (fromEnum o - 1)--intToOrdering :: CInt -> Ordering-intToOrdering i = compare i 0--peekOrdering :: Ptr CInt -> IO Ordering-peekOrdering = fmap intToOrdering . peek--withOrdering :: Ordering -> (Ptr CInt -> IO a) -> IO a-withOrdering o = with (orderingToInt o)
+ src/Sound/ALSA/PCM/Core/Class.hs view
@@ -0,0 +1,107 @@+module Sound.ALSA.PCM.Core.Class where++import qualified Sound.ALSA.PCM.Core.Handle as Core+import qualified Sound.ALSA.PCM.Core.HwParams as HwParams+import qualified Sound.ALSA.PCM.Core.SwParams as SwParams++import qualified Sound.Frame as Frame+import qualified Sound.Frame.Stereo as Stereo+import qualified Sound.Frame.MuLaw as MuLaw++import Data.Word (Word8, Word16, Word32, )+import Data.Int (Int8, Int16, Int32, )++import Foreign (Storable, )+++class Access i where+ access :: HwParams.T i y HwParams.Access+ setChannels :: (Frame.C y) => HwParams.T i y ()++instance Access Core.Interleaved where+ access = return HwParams.accessRwInterleaved+ setChannels =+ HwParams.setChannels . fromIntegral =<<+ withSampleFmt Frame.numberOfChannels++instance Access Core.Noninterleaved where+ access = return HwParams.accessRwNoninterleaved+ setChannels = return ()++++{-+We should have support for 24bit samples+that are packed on disk but padded to 32bit in memory.+-}+class (Storable y, Frame.C y) => SampleFmt y where+ sampleFmtToPcmFormat :: y -> HwParams.Format++instance SampleFmt Word8 where+ sampleFmtToPcmFormat _ = HwParams.formatU8++instance SampleFmt Int8 where+ sampleFmtToPcmFormat _ = HwParams.formatS8++instance SampleFmt Word16 where+ sampleFmtToPcmFormat _ = HwParams.formatU16++instance SampleFmt Int16 where+ sampleFmtToPcmFormat _ = HwParams.formatS16++instance SampleFmt Word32 where+ sampleFmtToPcmFormat _ = HwParams.formatU32++instance SampleFmt Int32 where+ sampleFmtToPcmFormat _ = HwParams.formatS32++instance SampleFmt Float where+ sampleFmtToPcmFormat _ = HwParams.formatFloat++instance SampleFmt Double where+ sampleFmtToPcmFormat _ = HwParams.formatFloat64++instance SampleFmt MuLaw.T where+ sampleFmtToPcmFormat _ = HwParams.formatMuLaw++instance SampleFmt a => SampleFmt (Stereo.T a) where+ sampleFmtToPcmFormat y =+ sampleFmtToPcmFormat (Stereo.left y)+++{- |+Sample types of this class must have exactly one channel,+i.e. Frame.numberOfChannels == 1.+-}+class (SampleFmt y) => MonoSampleFmt y where++instance MonoSampleFmt Word8 where+instance MonoSampleFmt Int8 where+instance MonoSampleFmt Word16 where+instance MonoSampleFmt Int16 where+instance MonoSampleFmt Word32 where+instance MonoSampleFmt Int32 where+instance MonoSampleFmt Float where+instance MonoSampleFmt Double where+instance MonoSampleFmt MuLaw.T where+++withSampleFmt :: (y -> a) -> HwParams.T i y a+withSampleFmt f = return $ f undefined+++withHwParams ::+ (Access i, SampleFmt y) =>+ Core.Handle i y -> HwParams.T i y a -> IO a+withHwParams h f =+ HwParams.withIO h $ (\(HwParams.Cons act) -> act h) $ do+ HwParams.setAccess =<< access+ HwParams.setFormat =<< withSampleFmt sampleFmtToPcmFormat+ setChannels+ f++withSwParams ::+ (Access i, SampleFmt y) =>+ Core.Handle i y -> SwParams.T i y a -> IO a+withSwParams h (SwParams.Cons f) =+ SwParams.withIO h $ f h
+ src/Sound/ALSA/PCM/Core/Convert.hs view
@@ -0,0 +1,34 @@+module Sound.ALSA.PCM.Core.Convert where++import qualified Foreign.Marshal.Utils as U+import qualified Foreign.Storable as St+import Foreign.Ptr (Ptr, )++import qualified Prelude as P+import Prelude hiding (id, )+++data T h c =+ Cons {fromHaskell :: h -> c, toHaskell :: c -> h}++with ::+ (St.Storable c) =>+ T h c -> h -> (Ptr c -> IO a) -> IO a+with conv a = U.with (fromHaskell conv a)++peek ::+ (St.Storable a) =>+ T h a -> Ptr a -> IO h+peek conv aptr = fmap (toHaskell conv) $ St.peek aptr+++id :: T a a+id = Cons P.id P.id++int :: (Integral a, Integral b) => T a b+int = Cons fromIntegral fromIntegral++{-+word :: T Word C.CUInt+word = Cons fromIntegral fromIntegral+-}
+ src/Sound/ALSA/PCM/Core/Handle.hsc view
@@ -0,0 +1,157 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module Sound.ALSA.PCM.Core.Handle where++import Sound.ALSA.Exception (checkResult, checkResult_, )++import qualified Foreign.Storable.Newtype as Store++import qualified Foreign.C.Types as C+import Foreign.C.String (CString, withCString, )+import Foreign.Ptr (Ptr, minusPtr, )+import Foreign.Storable (Storable, sizeOf, alignment, peek, poke, )+import Foreign.Marshal.Array (advancePtr, )+import Foreign.Marshal.Alloc (alloca, )++import Data.Bits ((.|.), )+import Data.Monoid (Monoid, mempty, mappend, mconcat, )++import Prelude hiding (any, )+++#include <alsa/asoundlib.h>+++data Struct i y = Struct++newtype Handle i y = Handle {dePcm :: Ptr (Struct i y)}++data Interleaved = Interleaved+data Noninterleaved = Noninterleaved+++instance Storable (Handle i y) where+ sizeOf = Store.sizeOf dePcm+ alignment = Store.alignment dePcm+ peek = Store.peek Handle+ poke = Store.poke dePcm+++type SampleFreq = Int+type Time = Int+type Size = Int+++data Stream =+ StreamPlayback+ | StreamCapture+ deriving (Eq,Show,Bounded)++instance Enum Stream where+ fromEnum StreamPlayback = #{const SND_PCM_STREAM_PLAYBACK}+ fromEnum StreamCapture = #{const SND_PCM_STREAM_CAPTURE}++ toEnum #{const SND_PCM_STREAM_PLAYBACK} = StreamPlayback+ toEnum #{const SND_PCM_STREAM_CAPTURE} = StreamCapture+ toEnum unmatched = error ("Stream.toEnum: Cannot match " ++ show unmatched)+++newtype Mode = Mode C.CInt++#{enum Mode, Mode,+ nonBlock = SND_PCM_NONBLOCK,+ async = SND_PCM_ASYNC }++instance Monoid Mode where+ mempty = Mode 0+ mappend (Mode a) (Mode b) = Mode (a .|. b)++modes :: [Mode] -> Mode+modes = mconcat+++foreign import ccall safe "alsa/pcm.h snd_pcm_open"+ open_ :: Ptr (Handle i y) -> CString -> C.CInt -> Mode -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_close"+ close_ :: Handle i y -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_prepare"+ prepare_ :: Handle i y -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_start"+ start_ :: Handle i y -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_drop"+ drop_ :: Handle i y -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_drain"+ drain_ :: Handle i y -> IO C.CInt+++open :: String -> Stream -> Mode -> IO (Handle i y)+open device dir mode =+ alloca $ \ptr ->+ withCString device $ \deviceCStr ->+ open_ ptr deviceCStr (fromIntegral $ fromEnum dir) mode >>=+ checkResult_ "PCM.open" >>+ peek ptr++close :: Handle i y -> IO ()+close h =+ close_ h >>= checkResult_ "PCM.close"++prepare :: Handle i y -> IO ()+prepare h =+ prepare_ h >>= checkResult_ "PCM.prepare"++start :: Handle i y -> IO ()+start h =+ start_ h >>= checkResult_ "PCM.start"++drop :: Handle i y -> IO ()+drop h =+ drop_ h >>= checkResult_ "PCM.drop"++drain :: Handle i y -> IO ()+drain h =+ drain_ h >>= checkResult_ "PCM.drain"++++foreign import ccall safe "alsa/pcm.h snd_pcm_readi"+ readi_ :: Handle Interleaved y -> Ptr y -> C.CULong -> IO C.CLong++foreign import ccall safe "alsa/pcm.h snd_pcm_writei"+ writei_ :: Handle Interleaved y -> Ptr y -> C.CULong -> IO C.CLong++foreign import ccall safe "alsa/pcm.h snd_pcm_readn"+ readn_ :: Handle Noninterleaved y -> Ptr (Ptr y) -> C.CULong -> IO C.CLong++foreign import ccall safe "alsa/pcm.h snd_pcm_writen"+ writen_ :: Handle Noninterleaved y -> Ptr (Ptr y) -> C.CULong -> IO C.CLong+++readi :: Handle Interleaved y -> Ptr y -> Size -> IO Size+readi h buf n =+ fmap fromIntegral $+ checkResult "PCM.readi" =<< readi_ h buf (fromIntegral n)++writei :: Handle Interleaved y -> Ptr y -> Size -> IO Size+writei h buf n =+ fmap fromIntegral $+ checkResult "PCM.writei" =<< writei_ h buf (fromIntegral n)++readn :: Handle Noninterleaved y -> Ptr (Ptr y) -> Size -> IO Size+readn h buf n =+ fmap fromIntegral $+ checkResult "PCM.readn" =<< readn_ h buf (fromIntegral n)++writen :: Handle Noninterleaved y -> Ptr (Ptr y) -> Size -> IO Size+writen h buf n =+ fmap fromIntegral $+ checkResult "PCM.writen" =<< writen_ h buf (fromIntegral n)+++{-# INLINE arraySize #-}+arraySize :: Storable y => Ptr y -> Int -> Int+arraySize p n = advancePtr p n `minusPtr` p
+ src/Sound/ALSA/PCM/Core/HwParams.hsc view
@@ -0,0 +1,382 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module Sound.ALSA.PCM.Core.HwParams where++import Sound.ALSA.PCM.Core.Handle (Handle, Time, Size, SampleFreq, )+import qualified Sound.ALSA.PCM.Core.Handle as H -- expose Handle constructor to FFI+import qualified Sound.ALSA.PCM.Core.Convert as Conv+import Sound.ALSA.PCM.Core.Convert (fromHaskell, )++import Sound.ALSA.Exception (checkResult, checkResult_, )++import Control.Applicative (Applicative(pure, (<*>)))++import Control.Exception (bracket, )++import qualified Foreign.Storable.Newtype as Store++import qualified Foreign.C.Types as C+import qualified Foreign.C.Error as E+import Foreign.Ptr (Ptr, )+import Foreign.Storable (Storable, sizeOf, alignment, peek, poke, )+import Foreign.Marshal.Alloc (alloca, )++import Data.Word (Word, )++import Prelude hiding (any, )++#include <alsa/asoundlib.h>+#include <Sound/ALSA/PCM/Core/Params.h>++++newtype T i y a = Cons (H.Handle i y -> Ptr Params -> IO a)++data Params = Params+++{-+T is a Reader monad.+-}+instance Functor (T i y) where+ fmap f (Cons act) = Cons $ \h p -> fmap f $ act h p++instance Applicative (T i y) where+ pure a = Cons $ \ _h _p -> pure a+ Cons f <*> Cons x = Cons $ \h p -> f h p <*> x h p++instance Monad (T i y) where+ return a = Cons $ \ _h _p -> return a+ Cons x >>= k =+ Cons $ \h p -> x h p >>= \a -> case k a of Cons y -> y h p++++withIO :: Handle i y -> (Ptr Params -> IO a) -> IO a+withIO h f =+ bracket malloc free $ \p -> do+ any h p+ x <- f p+ set h p+ return x+-- bracket_ (any h p) (set h p) (f p)+++foreign import ccall safe "alsa/pcm.h snd_pcm_hw_params_malloc"+ malloc_ :: Ptr (Ptr Params) -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_hw_params_free"+ free :: Ptr Params -> IO ()++malloc :: IO (Ptr Params)+malloc =+ alloca $ \pp ->+ malloc_ pp >>=+ checkResult_ "HwParams.malloc" >>+ peek pp++++foreign import ccall safe "alsa/pcm.h snd_pcm_hw_params"+ set_ :: Handle i y -> Ptr Params -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_hw_params_any"+ any_ :: Handle i y -> Ptr Params -> IO C.CInt++set :: Handle i y -> Ptr Params -> IO ()+set h p =+ set_ h p >>= checkResult_ "HwParams.set"++any :: Handle i y -> Ptr Params -> IO ()+any h p =+ any_ h p >>= checkResult_ "HwParams.any"++-- #accessor checked, "any", pcm_params, NULL+++newtype Bool_ = Bool_ {fromBool_ :: C.CInt}+ deriving (Eq, Ord)++instance Storable Bool_ where+ sizeOf = Store.sizeOf fromBool_+ alignment = Store.alignment fromBool_+ peek = Store.peek Bool_+ poke = Store.poke fromBool_++boolConv :: Conv.T Bool Bool_+boolConv =+ Conv.Cons+ (\b -> Bool_ $ fromIntegral $ fromEnum b)+ (Bool_ 0 /=)+++newtype Direction = Direction {fromDirection :: C.CInt}+ deriving (Eq, Ord)++instance Storable Direction where+ sizeOf = Store.sizeOf fromDirection+ alignment = Store.alignment fromDirection+ peek = Store.peek Direction+ poke = Store.poke fromDirection++ordConv :: Conv.T Ordering Direction+ordConv =+ Conv.Cons+ (\o -> Direction $ fromIntegral $ fromEnum o - 1)+ (\d -> compare d $ Direction 0)+++newtype Access = Access {fromAccess :: C.CInt}+ deriving (Eq, Ord)++instance Enum Access where+ toEnum n = Access $ fromIntegral n+ fromEnum (Access n) = fromIntegral n++instance Bounded Access where+ minBound = Access #{const SND_PCM_ACCESS_MMAP_INTERLEAVED}+ maxBound = Access #{const SND_PCM_ACCESS_LAST}++instance Storable Access where+ sizeOf = Store.sizeOf fromAccess+ alignment = Store.alignment fromAccess+ peek = Store.peek Access+ poke = Store.poke fromAccess++#{enum Access, Access,+ accessMmapInterleaved = SND_PCM_ACCESS_MMAP_INTERLEAVED,+ accessMmapNoninterleaved = SND_PCM_ACCESS_MMAP_NONINTERLEAVED,+ accessMmapComplex = SND_PCM_ACCESS_MMAP_COMPLEX,+ accessRwInterleaved = SND_PCM_ACCESS_RW_INTERLEAVED,+ accessRwNoninterleaved = SND_PCM_ACCESS_RW_NONINTERLEAVED }++++newtype Format = Format {fromFormat :: C.CInt}+ deriving (Eq, Ord)++instance Enum Format where+ toEnum n = Format $ fromIntegral n+ fromEnum (Format n) = fromIntegral n++instance Bounded Format where+ minBound = formatUnknown+ maxBound = Format #{const SND_PCM_FORMAT_LAST}++instance Storable Format where+ sizeOf = Store.sizeOf fromFormat+ alignment = Store.alignment fromFormat+ peek = Store.peek Format+ poke = Store.poke fromFormat++#{enum Format, Format,+ formatUnknown = SND_PCM_FORMAT_UNKNOWN,+ formatS8 = SND_PCM_FORMAT_S8,+ formatU8 = SND_PCM_FORMAT_U8,+ formatS16Le = SND_PCM_FORMAT_S16_LE,+ formatS16Be = SND_PCM_FORMAT_S16_BE,+ formatU16Le = SND_PCM_FORMAT_U16_LE,+ formatU16Be = SND_PCM_FORMAT_U16_BE,+ formatS24Le = SND_PCM_FORMAT_S24_LE,+ formatS24Be = SND_PCM_FORMAT_S24_BE,+ formatU24Le = SND_PCM_FORMAT_U24_LE,+ formatU24Be = SND_PCM_FORMAT_U24_BE,+ formatS32Le = SND_PCM_FORMAT_S32_LE,+ formatS32Be = SND_PCM_FORMAT_S32_BE,+ formatU32Le = SND_PCM_FORMAT_U32_LE,+ formatU32Be = SND_PCM_FORMAT_U32_BE,+ formatFloatLe = SND_PCM_FORMAT_FLOAT_LE,+ formatFloatBe = SND_PCM_FORMAT_FLOAT_BE,+ formatFloat64Le = SND_PCM_FORMAT_FLOAT64_LE,+ formatFloat64Be = SND_PCM_FORMAT_FLOAT64_BE,+ formatIec958SubframeLe = SND_PCM_FORMAT_IEC958_SUBFRAME_LE,+ formatIec958SubframeBe = SND_PCM_FORMAT_IEC958_SUBFRAME_BE,+ formatMuLaw = SND_PCM_FORMAT_MU_LAW,+ formatALaw = SND_PCM_FORMAT_A_LAW,+ formatImaAdpcm = SND_PCM_FORMAT_IMA_ADPCM,+ formatMpeg = SND_PCM_FORMAT_MPEG,+ formatGsm = SND_PCM_FORMAT_GSM,+ formatSpecial = SND_PCM_FORMAT_SPECIAL,+ formatS243le = SND_PCM_FORMAT_S24_3LE,+ formatS243be = SND_PCM_FORMAT_S24_3BE,+ formatU243le = SND_PCM_FORMAT_U24_3LE,+ formatU243be = SND_PCM_FORMAT_U24_3BE,+ formatS203le = SND_PCM_FORMAT_S20_3LE,+ formatS203be = SND_PCM_FORMAT_S20_3BE,+ formatU203le = SND_PCM_FORMAT_U20_3LE,+ formatU203be = SND_PCM_FORMAT_U20_3BE,+ formatS183le = SND_PCM_FORMAT_S18_3LE,+ formatS183be = SND_PCM_FORMAT_S18_3BE,+ formatU183le = SND_PCM_FORMAT_U18_3LE,+ formatU183be = SND_PCM_FORMAT_U18_3BE,+ formatS16 = SND_PCM_FORMAT_S16,+ formatU16 = SND_PCM_FORMAT_U16,+ formatS24 = SND_PCM_FORMAT_S24,+ formatU24 = SND_PCM_FORMAT_U24,+ formatS32 = SND_PCM_FORMAT_S32,+ formatU32 = SND_PCM_FORMAT_U32,+ formatFloat = SND_PCM_FORMAT_FLOAT,+ formatFloat64 = SND_PCM_FORMAT_FLOAT64,+ formatIec958Subframe = SND_PCM_FORMAT_IEC958_SUBFRAME }+++newtype Subformat = Subformat {fromSubformat :: C.CUInt}+ deriving (Eq, Ord)++instance Storable Subformat where+ sizeOf = Store.sizeOf fromSubformat+ alignment = Store.alignment fromSubformat+ peek = Store.peek Subformat+ poke = Store.poke fromSubformat++++#accessor boolresult, "can_mmap_sample_resolution", params_only, NULL+#accessor boolresult, "is_double", params_only, NULL+#accessor boolresult, "is_batch", params_only, NULL+#accessor boolresult, "is_block_transfer", params_only, NULL+#accessor boolresult, "can_overrange", params_only, NULL+#accessor boolresult, "can_pause", params_only, NULL+#accessor boolresult, "can_resume", params_only, NULL+#accessor boolresult, "is_half_duplex", params_only, NULL+#accessor boolresult, "is_joint_duplex", params_only, NULL+#accessor boolresult, "can_sync_start", params_only, NULL+++#accessor checked, "get_rate_numden", params_only, \+ out(&uint_p, "rateNum"), out(&uint_p, "rateDen"), NULL+#accessor uintresult, "get_sbits", params_only, NULL+#accessor uintresult, "get_fifo_size", params_only, NULL++#accessor checked, "get_access", params_only, out(&access_p, "access"), NULL+#accessor errnoresult, "test_access", pcm_params, in(&access_p, "access"), NULL+#accessor checked, "set_access", pcm_params, in(&access_p, "access"), NULL+#accessor checked, "set_access_first", pcm_params, inout(&access_p, "access"), NULL+#accessor checked, "set_access_last", pcm_params, inout(&access_p, "access"), NULL+{- in order to use this, we would have to implement mask accessors, too+#accessor checked, "set_access_mask", pcm_params, inout(&access_mask, "mask"), NULL+#accessor checked, "get_access_mask", params_only, out(&access_mask, "mask"), NULL+-}++#accessor checked, "get_format", params_only, out(&format_p, "val"), NULL+#accessor errnoresult, "test_format", pcm_params, in(&format_p, "val"), NULL+#accessor checked, "set_format", pcm_params, in(&format_p, "val"), NULL+#accessor checked, "set_format_first", pcm_params, inout(&format_p, "format"), NULL+#accessor checked, "set_format_last", pcm_params, inout(&format_p, "format"), NULL+{-+#accessor checked, "set_format_mask", pcm_params, inout(&format_mask_p, "mask"), NULL+#accessor noresult, "get_format_mask", params_only, out(&format_mask_p, "mask"), NULL+-}++#accessor checked, "get_subformat", params_only, out(&subformat_p, "subformat"), NULL+#accessor errnoresult, "test_subformat", pcm_params, in(&subformat_p, "subformat"), NULL+#accessor checked, "set_subformat", pcm_params, in(&subformat_p, "subformat"), NULL+#accessor checked, "set_subformat_first", pcm_params, inout(&subformat_p, "subformat"), NULL+#accessor checked, "set_subformat_last", pcm_params, inout(&subformat_p, "subformat"), NULL+{-+#accessor checked, "set_subformat_mask", pcm_params, inout(&subformat_mask_p, "mask"), NULL+#accessor noresult, "get_subformat_mask", params_only, out(&subformat_mask_p, "mask"), NULL+-}++#accessor checked, "get_channels", params_only, out(&uint_p, "val"), NULL+#accessor checked, "get_channels_min", params_only, out(&uint_p, "val"), NULL+#accessor checked, "get_channels_max", params_only, out(&uint_p, "val"), NULL+#accessor errnoresult, "test_channels", pcm_params, in(&uint_p, "val"), NULL+#accessor checked, "set_channels", pcm_params, in(&uint_p, "val"), NULL+#accessor checked, "set_channels_min", pcm_params, inout(&uint_p, "val"), NULL+#accessor checked, "set_channels_max", pcm_params, inout(&uint_p, "val"), NULL+#accessor checked, "set_channels_minmax", pcm_params, inout(&uint_p, "vmin"), inout(&uint_p, "vmax"), NULL+#accessor checked, "set_channels_near", pcm_params, inout(&uint_p, "val"), NULL+#accessor checked, "set_channels_first", pcm_params, inout(&uint_p, "val"), NULL+#accessor checked, "set_channels_last", pcm_params, inout(&uint_p, "val"), NULL++#accessor checked, "get_rate", params_only, out(&rate_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_rate_min", params_only, out(&rate_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_rate_max", params_only, out(&rate_p, "val"), out(&direction_p, "dir"), NULL+#accessor errnoresult, "test_rate", pcm_params, in(&rate_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_rate", pcm_params, in(&rate_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_rate_min", pcm_params, inout(&rate_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_rate_max", pcm_params, inout(&rate_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_rate_minmax", pcm_params, inout(&rate_p, "vmin"), inout(&direction_p, "mindir"), inout(&rate_p, "vmax"), inout(&direction_p, "maxdir"), NULL+#accessor checked, "set_rate_near", pcm_params, inout(&rate_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_rate_first", pcm_params, inout(&rate_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_rate_last", pcm_params, inout(&rate_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_rate_resample", pcm_params, in(&bool_p, "val"), NULL+#accessor checked, "get_rate_resample", pcm_params, out(&bool_p, "val"), NULL+#accessor checked, "set_export_buffer", pcm_params, in(&bool_p, "val"), NULL+#accessor checked, "get_export_buffer", pcm_params, out(&bool_p, "val"), NULL++#accessor checked, "get_period_time", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_period_time_min", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_period_time_max", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor errnoresult, "test_period_time", pcm_params, in(&time_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_period_time", pcm_params, in(&time_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_period_time_min", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_time_max", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_time_minmax", pcm_params, inout(&time_p, "vmin"), inout(&direction_p, "mindir"), inout(&time_p, "vmax"), inout(&direction_p, "maxdir"), NULL+#accessor checked, "set_period_time_near", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_time_first", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_time_last", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL++#accessor checked, "get_period_size", params_only, out(&uframes_p, "frames"), out(&direction_p, "dir"), NULL+#accessor checked, "get_period_size_min", params_only, out(&uframes_p, "frames"), out(&direction_p, "dir"), NULL+#accessor checked, "get_period_size_max", params_only, out(&uframes_p, "frames"), out(&direction_p, "dir"), NULL+#accessor errnoresult, "test_period_size", pcm_params, in(&uframes_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_period_size", pcm_params, in(&uframes_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_period_size_min", pcm_params, inout(&uframes_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_size_max", pcm_params, inout(&uframes_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_size_minmax", pcm_params, inout(&uframes_p, "vmin"), inout(&direction_p, "mindir"), inout(&uframes_p, "vmax"), inout(&direction_p, "maxdir"), NULL+#accessor checked, "set_period_size_near", pcm_params, inout(&uframes_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_size_first", pcm_params, inout(&uframes_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_size_last", pcm_params, inout(&uframes_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_period_size_integer", pcm_params, NULL++#accessor checked, "get_periods", params_only, out(&uint_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_periods_min", params_only, out(&uint_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_periods_max", params_only, out(&uint_p, "val"), out(&direction_p, "dir"), NULL+#accessor errnoresult, "test_periods", pcm_params, in(&uint_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_periods", pcm_params, in(&uint_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_periods_min", pcm_params, inout(&uint_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_periods_max", pcm_params, inout(&uint_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_periods_minmax", pcm_params, inout(&uint_p, "vmin"), inout(&direction_p, "mindir"), inout(&uint_p, "vmax"), inout(&direction_p, "maxdir"), NULL+#accessor checked, "set_periods_near", pcm_params, inout(&uint_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_periods_first", pcm_params, inout(&uint_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_periods_last", pcm_params, inout(&uint_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_periods_integer", pcm_params, NULL++#accessor checked, "get_buffer_time", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_buffer_time_min", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_buffer_time_max", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor errnoresult, "test_buffer_time", pcm_params, in(&time_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_buffer_time", pcm_params, in(&time_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_buffer_time_min", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_buffer_time_max", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_buffer_time_minmax", pcm_params, inout(&time_p, "vmin"), inout(&direction_p, "mindir"), inout(&time_p, "vmax"), inout(&direction_p, "maxdir"), NULL+#accessor checked, "set_buffer_time_near", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_buffer_time_first", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_buffer_time_last", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL++#accessor checked, "get_buffer_size", params_only, out(&uframes_p, "val"), NULL+#accessor checked, "get_buffer_size_min", params_only, out(&uframes_p, "val"), NULL+#accessor checked, "get_buffer_size_max", params_only, out(&uframes_p, "val"), NULL+#accessor errnoresult, "test_buffer_size", pcm_params, in(&uframes_p, "val"), NULL+#accessor checked, "set_buffer_size", pcm_params, in(&uframes_p, "val"), NULL+#accessor checked, "set_buffer_size_min", pcm_params, inout(&uframes_p, "val"), NULL+#accessor checked, "set_buffer_size_max", pcm_params, inout(&uframes_p, "val"), NULL+#accessor checked, "set_buffer_size_minmax", pcm_params, inout(&uframes_p, "vmin"), inout(&uframes_p, "vmax"), NULL+#accessor checked, "set_buffer_size_near", pcm_params, inout(&uframes_p, "val"), NULL+#accessor checked, "set_buffer_size_first", pcm_params, inout(&uframes_p, "val"), NULL+#accessor checked, "set_buffer_size_last", pcm_params, inout(&uframes_p, "val"), NULL++#accessor checked, "get_tick_time", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_tick_time_min", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor checked, "get_tick_time_max", params_only, out(&time_p, "val"), out(&direction_p, "dir"), NULL+#accessor errnoresult, "test_tick_time", pcm_params, in(&time_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_tick_time", pcm_params, in(&time_p, "val"), in(&direction_p, "dir"), NULL+#accessor checked, "set_tick_time_min", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_tick_time_max", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_tick_time_minmax", pcm_params, inout(&time_p, "vmin"), inout(&direction_p, "mindir"), inout(&time_p, "vmax"), inout(&direction_p, "maxdir"), NULL+#accessor checked, "set_tick_time_near", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_tick_time_first", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL+#accessor checked, "set_tick_time_last", pcm_params, inout(&time_p, "val"), inout(&direction_p, "dir"), NULL++#accessor checked, "get_min_align", params_only, out(&uframes_p, "val"), NULL
+ src/Sound/ALSA/PCM/Core/Params.h view
@@ -0,0 +1,247 @@+#include <stdlib.h>+#include <stdarg.h>++typedef char bool;+const bool false = 0, true = 1;++enum context {pcm_params, params_only};++void make_camel_case (char *dst, const char *src) {+ while (*src != 0) {+ if (*src == '_') {+ src ++;+ if (*src == 0) {break;}+ *dst = *src - ('a'-'A'); // assumes that 'a'>'A'+ } else {+ *dst = *src;+ }+ src++;+ dst++;+ }+ *dst = 0;+}++void init_comma (bool *comma) {+ *comma = false;+}++void print_comma (bool *comma) {+ if (*comma) {+ printf(", ");+ }+ *comma = true;+}++struct type {+ char *convert;+ char *hsname;+ char *cname;+};++enum param_direction {dir_in, dir_out, dir_inout};++struct parameter {+ struct type *type;+ char *name;+ enum param_direction dir;+};++struct parameter *in (struct type* t, char *name) {+ struct parameter *p = malloc (sizeof(struct parameter));+ p->type = t;+ p->name = name;+ p->dir = dir_in;+ return p;+}++struct parameter *out (struct type* t, char *name) {+ struct parameter *p = malloc (sizeof(struct parameter));+ p->type = t;+ p->name = name;+ p->dir = dir_out;+ return p;+}++struct parameter *inout (struct type* t, char *name) {+ struct parameter *p = malloc (sizeof(struct parameter));+ p->type = t;+ p->name = name;+ p->dir = dir_inout;+ return p;+}+++struct type bool_p = {"boolConv", "Bool", "Bool_"};++struct type uint_p = {"Conv.int", "Word", "C.CUInt"};++struct type rate_p = {"Conv.int", "SampleFreq", "C.CUInt"};++struct type time_p = {"Conv.int", "Time", "C.CUInt"};++struct type direction_p = {"ordConv", "Ordering", "Direction"};++struct type uframes_p = {"Conv.int", "Size", "C.CUInt"};++struct type access_p = {"Conv.id", "Access", "Access"};++struct type format_p = {"Conv.id", "Format", "Format"};++struct type subformat_p = {"Conv.id", "Subformat", "Subformat"};++enum result {noresult, boolresult, uintresult, errnoresult, checked};+++void hsc_accessor (enum result res, const char *name, enum context ctx, ...) {+ va_list arg;+ struct parameter *p;+ bool comma;+ char *camelName = alloca (strlen (name) + 1);+ make_camel_case (camelName, name);++ printf("foreign import ccall safe \"alsa/pcm.h snd_pcm_hw_params_%s\"\n",+ name);+ printf(" %s_ :: ", camelName);+ if (ctx==pcm_params) {+// printf("Ptr (Struct i y) -> Ptr Params -> ");+ printf("Handle i y -> Ptr Params -> ");+ } else {+ printf("Ptr Params -> ");+ }++ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir == dir_in) {+ printf("%s -> ", p->type->cname);+ } else {+ printf("Ptr %s -> ", p->type->cname);+ }+ }+ va_end (arg);++ printf("IO ");+ if (res == noresult) {+ printf("()");+ } else if (res == errnoresult) {+ printf("E.Errno");+ } else {+ printf("C.CInt");+ }+ printf("\n\n");++ printf("%s :: ", camelName);++ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir != dir_out) {+ printf("%s -> ", p->type->hsname);+ }+ }+ va_end (arg);++ printf("T i y (");+ init_comma(&comma);+ if (res == uintresult) {+ print_comma(&comma);+ printf("Word");+ } else if (res == errnoresult) {+ print_comma(&comma);+ printf("E.Errno");+ } else if (res == boolresult) {+ print_comma(&comma);+ printf("Bool");+ }+ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir != dir_in) {+ print_comma(&comma);+ printf("%s", p->type->hsname);+ }+ }+ va_end (arg);+ printf(")\n");++ printf("%s", camelName);+ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir != dir_out) {+ printf(" %s", p->name);+ }+ }+ va_end (arg);+ printf(" =\n");++ if (ctx==pcm_params) {+// printf(" Cons $ \\(Handle h) p ->\n");+ printf(" Cons $ \\h p ->\n");+ } else {+ printf(" Cons $ \\ _ p ->\n");+ }+ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir == dir_out) {+ printf(" alloca $ \\%sPtr ->\n", p->name);+ } else if (p->dir == dir_inout) {+ printf(" Conv.with %s %s $ \\%sPtr ->\n",+ p->type->convert, p->name, p->name);+ }+ }+ va_end (arg);++ printf(" %s_", camelName);+ if (ctx==pcm_params) {+ printf(" h p");+ } else {+ printf(" p");+ }+ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir == dir_in) {+ printf(" (fromHaskell %s %s)",+ p->type->convert, p->name);+ } else {+ printf(" %sPtr", p->name);+ }+ }+ va_end (arg);+ if (res == uintresult) {+ printf(" >>=\n checkResult \"HwParams.%s\" >>= \\res ->\n", camelName);+ } else if (res == boolresult || res == errnoresult) {+ printf(" >>= \\res ->\n");+ } else if (res == checked) {+ printf(" >>=\n checkResult_ \"HwParams.%s\" >>\n", camelName);+ } else {+ printf(" >>\n");+ }++ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir != dir_in) {+ printf(" Conv.peek %s %sPtr >>= \\%sResult ->\n",+ p->type->convert, p->name, p->name);+ }+ }+ va_end (arg);++ printf(" return (");+ init_comma(&comma);+ if (res == uintresult) {+ print_comma(&comma);+ printf("fromIntegral res");+ } else if (res == errnoresult) {+ print_comma(&comma);+ printf("res");+ } else if (res == boolresult) {+ print_comma(&comma);+ printf("res/=0");+ }+ va_start (arg, ctx);+ while (p = va_arg (arg, struct parameter *)) {+ if (p->dir != dir_in) {+ print_comma(&comma);+ printf("%sResult", p->name);+ }+ }+ va_end (arg);+ printf(")\n");+}
+ src/Sound/ALSA/PCM/Core/SwParams.hsc view
@@ -0,0 +1,138 @@+{-# LANGUAGE ForeignFunctionInterface #-}+module Sound.ALSA.PCM.Core.SwParams where++import Sound.ALSA.PCM.Core.Handle (Handle, Size, )+import qualified Sound.ALSA.PCM.Core.Handle as H -- expose Handle constructor to FFI+import qualified Sound.ALSA.PCM.Core.Convert as Conv++import Sound.ALSA.Exception (checkResult_, )++import Control.Applicative (Applicative(pure, (<*>)))++import Control.Exception (bracket, )++import qualified Foreign.Storable.Newtype as Store++import qualified Foreign.C.Types as C+import Foreign.Ptr (Ptr, )+import Foreign.Storable (Storable, sizeOf, alignment, peek, poke, )+import Foreign.Marshal.Alloc (alloca, )++import Data.Word (Word, )+++#include <alsa/asoundlib.h>++newtype T i y a = Cons (H.Handle i y -> Ptr Params -> IO a)++data Params = Params+++{-+T is a Reader monad.+-}+instance Functor (T i y) where+ fmap f (Cons act) = Cons $ \h p -> fmap f $ act h p++instance Applicative (T i y) where+ pure a = Cons $ \ _h _p -> pure a+ Cons f <*> Cons x = Cons $ \h p -> f h p <*> x h p++instance Monad (T i y) where+ return a = Cons $ \ _h _p -> return a+ Cons x >>= k =+ Cons $ \h p -> x h p >>= \a -> case k a of Cons y -> y h p++++withIO :: Handle i y -> (Ptr Params -> IO a) -> IO a+withIO h f =+ bracket malloc free $ \p -> do+ current h p+ x <- f p+ set h p+ return x+-- bracket_ (current h p) (set h p) (f p)+++foreign import ccall safe "alsa/pcm.h snd_pcm_sw_params_malloc"+ malloc_ :: Ptr (Ptr Params) -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_sw_params_free"+ free :: Ptr Params -> IO ()++malloc :: IO (Ptr Params)+malloc =+ alloca $ \pp ->+ malloc_ pp >>=+ checkResult_ "SwParams.malloc" >>+ peek pp++++foreign import ccall safe "alsa/pcm.h snd_pcm_sw_params"+ set_ :: Handle i y -> Ptr Params -> IO C.CInt++foreign import ccall safe "alsa/pcm.h snd_pcm_sw_params_current"+ current_ :: Handle i y -> Ptr Params -> IO C.CInt++set :: Handle i y -> Ptr Params -> IO ()+set h p =+ set_ h p >>= checkResult_ "SwParams.set"++current :: Handle i y -> Ptr Params -> IO ()+current h p =+ current_ h p >>= checkResult_ "SwParams.current"++++newtype TimestampMode = TimestampMode {fromTimestampMode :: C.CInt}+ deriving (Eq, Ord)++instance Enum TimestampMode where+ toEnum n = TimestampMode $ fromIntegral n+ fromEnum (TimestampMode n) = fromIntegral n++instance Storable TimestampMode where+ sizeOf = Store.sizeOf fromTimestampMode+ alignment = Store.alignment fromTimestampMode+ peek = Store.peek TimestampMode+ poke = Store.poke fromTimestampMode++#{enum TimestampMode, TimestampMode,+ timestampNone = SND_PCM_TSTAMP_NONE,+ timestampMmap = SND_PCM_TSTAMP_MMAP}++++#{let accessor hsName, cName, conv, hsType, cType =+"foreign import ccall safe \"alsa/pcm.h snd_pcm_sw_params_set_"cName"\"\n"+" set"hsName"_ :: Handle i y -> Ptr Params -> "cType" -> IO C.CInt\n"+"\n"+"foreign import ccall safe \"alsa/pcm.h snd_pcm_sw_params_get_"cName"\"\n"+" get"hsName"_ :: Ptr Params -> Ptr "cType" -> IO C.CInt\n"+"\n"+"set"hsName" :: "hsType" -> T i y ()\n"+"set"hsName" x =\n"+" Cons $ \\h p ->\n"+" set"hsName"_ h p (Conv.fromHaskell "conv" x) >>=\n"+" checkResult_ \"SwParams.set"hsName"\"\n"+"\n"+"get"hsName" :: T i y "hsType"\n"+"get"hsName" =\n"+" Cons $ \\_ p ->\n"+" alloca $ \\ptr ->\n"+" get"hsName"_ p ptr >>=\n"+" checkResult_ \"SwParams.get"hsName"\" >>\n"+" Conv.peek "conv" ptr\n"+}+++#accessor "TimestampMode", "tstamp_mode", "Conv.id", "TimestampMode", "TimestampMode"+#accessor "SleepMin", "sleep_min", "Conv.int", "Word", "C.CUInt"+#accessor "AvailMin", "avail_min", "Conv.int", "Size", "C.CULong"+#accessor "XferAlign", "xfer_align", "Conv.int", "Size", "C.CULong"+#accessor "StartThreshold", "start_threshold", "Conv.int", "Size", "C.CULong"+#accessor "StopThreshold", "stop_threshold", "Conv.int", "Size", "C.CULong"+#accessor "SilenceThreshold", "silence_threshold", "Conv.int", "Size", "C.CULong"+#accessor "SilenceSize", "silence_size", "Conv.int", "Size", "C.CULong"
+ src/Sound/ALSA/PCM/Node/ALSA.hs view
@@ -0,0 +1,126 @@+module Sound.ALSA.PCM.Node.ALSA (+ -- * Types+ Handle,+ PCM.Stream(..),+ PCM.Mode, PCM.modes, PCM.nonBlock, PCM.async,+ Interleaved, Noninterleaved,+ Time, SampleFreq, Size,+ -- * Classes+ Class.Access, Class.SampleFmt, Class.MonoSampleFmt,+ -- * Management of streams+ open,+ PCM.close,+ PCM.prepare,+ PCM.start,+ PCM.drop,+ PCM.drain,+ -- * Data transfer+ readi, writei, readiRetry, writeiRetry,+ readn, writen,+ ) where++import Sound.ALSA.PCM.Parameters.Hardware (Time, SampleFreq, Size, )+import Sound.ALSA.PCM.Core.Handle (Handle, Interleaved, Noninterleaved, prepare, )+import qualified Sound.ALSA.PCM.Parameters.Software as SwParam+import qualified Sound.ALSA.PCM.Parameters.Hardware as HwParam+import qualified Sound.ALSA.PCM.Core.Class as Class+import qualified Sound.ALSA.PCM.Core.Handle as PCM+import qualified Sound.ALSA.PCM.Debug as Debug+import qualified Sound.ALSA.Exception as AlsaExc++import Foreign.Marshal.Array (advancePtr, )+import Foreign (Ptr, )+++open ::+ (Class.Access i, Class.SampleFmt y) =>+ PCM.Mode+ -> PCM.Stream+ -> HwParam.T i y a+ -> (a -> SwParam.T i y b)+ -> String -- ^ device, e.g @\"default\"@+ -> IO (b, Handle i y)+open mode stream hwp swp dev = do+ h <- PCM.open dev stream mode+ a <- Class.withHwParams h hwp+ b <- Class.withSwParams h $ swp a+ return (b, h)+++readi ::+ (Class.SampleFmt y) =>+ Handle Interleaved y -> Ptr y -> Size -> IO Size+readi = PCM.readi++writei ::+ (Class.SampleFmt y) =>+ Handle Interleaved y -> Ptr y -> Size -> IO Size+writei = PCM.writei++{- |+The @Ptr (Ptr y)@ argument is actually a pointer to an array of pointers.+The array must have the size of number of channels.+In 'Noninterleaved' mode you must set the number of channels manually+using 'HwParam.setChannels' or its friends.+It is an unchecked error if the number of channels+set with 'HwParam.setChannels'+does not match the array size in the 'readn' call.+-}+readn ::+ (Class.MonoSampleFmt y) =>+ Handle Noninterleaved y -> Ptr (Ptr y) -> Size -> IO Size+readn = PCM.readn++{- |+Cf. 'readn'.+-}+writen ::+ (Class.MonoSampleFmt y) =>+ Handle Noninterleaved y -> Ptr (Ptr y) -> Size -> IO Size+writen = PCM.writen++++{- |+retry on buffer over-run+-}+readiRetry ::+ Class.SampleFmt y =>+ Handle Interleaved y -> Ptr y -> Size -> IO Size+readiRetry h buf0 n =+ let go buf offset = do+ -- debug $ "Reading " ++ show n ++ " samples..."+ nread <-+ readi h buf (n-offset)+ `AlsaExc.catchXRun`+ do Debug.put "snd_pcm_readi reported buffer over-run"+ prepare h+ go buf offset+ let newOffset = offset+nread+ -- debug $ "Got " ++ show n' ++ " samples."+ if newOffset < n+ then go (advancePtr buf (fromIntegral nread)) newOffset+ else return newOffset+ in go buf0 0++{- |+retry on buffer under-run+-}+writeiRetry ::+ Class.SampleFmt y =>+ Handle Interleaved y -> Ptr y -> Size -> IO Size+writeiRetry h buf0 n =+ let go buf offset = do+ -- debug $ "Writing " ++ show n ++ " samples..."+ nwritten <-+ writei h buf (n-offset)+ `AlsaExc.catchXRun`+ do Debug.put "snd_pcm_writei reported buffer under-run"+ prepare h+ go buf offset+ let newOffset = offset+nwritten+ --debug $ "Wrote " ++ show n' ++ " samples."+ if newOffset < n+ then go (advancePtr buf (fromIntegral nwritten)) newOffset+ else return newOffset+ in go buf0 0
+ src/Sound/ALSA/PCM/Node/File.hs view
@@ -0,0 +1,60 @@+module Sound.ALSA.PCM.Node.File (+ -- * Types+ Handle,+ Time, SampleFreq, Size,+ -- * Classes+ Class.SampleFmt,+ -- * Management of streams+ open, close,+ -- * Data transfer+ read, write,+ ) where++import qualified Sound.ALSA.PCM.Core.Class as Class+import Sound.ALSA.PCM.Parameters.Hardware (Time, SampleFreq, Size, )+import Sound.ALSA.PCM.Core.Handle (arraySize, )++import Control.Monad (liftM, )+import Foreign.Ptr (Ptr, )+import qualified System.IO as IO+import System.IO (IOMode, openBinaryFile, )++import Prelude hiding (read, )+++newtype Handle y = Handle IO.Handle+++open ::+ (Class.SampleFmt y) =>+ IOMode -> FilePath -> IO (Handle y)+open mode path =+ fmap Handle $ openBinaryFile path mode++close ::+ (Class.SampleFmt y) =>+ Handle y -> IO ()+close (Handle h) =+ IO.hClose h++{- |+This expects pad bytes that are needed in memory+in order to satisfy aligment constraints.+This is only a problem for samples sizes like 24 bit.+-}+read ::+ (Class.SampleFmt y) =>+ Handle y -> Ptr y -> Size -> IO Size+read (Handle h) buf n =+ liftM fromIntegral $+ liftM (`div` arraySize buf 1) $+ IO.hGetBuf h buf (arraySize buf (fromIntegral n))++{- |+Same restrictions as for 'fileRead'.+-}+write ::+ (Class.SampleFmt y) =>+ Handle y -> Ptr y -> Size -> IO ()+write (Handle h) buf n =+ IO.hPutBuf h buf (arraySize buf (fromIntegral n))
+ src/Sound/ALSA/PCM/Parameters/Hardware.hs view
@@ -0,0 +1,262 @@+module Sound.ALSA.PCM.Parameters.Hardware (+ -- * Types+ T, SampleFreq, Time, Size,+ Interleaved, Noninterleaved,++{-+ HwParams.Access,+ HwParams.accessMmapInterleaved,+ HwParams.accessMmapNoninterleaved,+ HwParams.accessMmapComplex,+ HwParams.accessRwInterleaved,+ HwParams.accessRwNoninterleaved,++ HwParams.Format,+ HwParams.formatUnknown,+ HwParams.formatS8,+ HwParams.formatU8,+ HwParams.formatS16Le,+ HwParams.formatS16Be,+ HwParams.formatU16Le,+ HwParams.formatU16Be,+ HwParams.formatS24Le,+ HwParams.formatS24Be,+ HwParams.formatU24Le,+ HwParams.formatU24Be,+ HwParams.formatS32Le,+ HwParams.formatS32Be,+ HwParams.formatU32Le,+ HwParams.formatU32Be,+ HwParams.formatFloatLe,+ HwParams.formatFloatBe,+ HwParams.formatFloat64Le,+ HwParams.formatFloat64Be,+ HwParams.formatIec958SubframeLe,+ HwParams.formatIec958SubframeBe,+ HwParams.formatMuLaw,+ HwParams.formatALaw,+ HwParams.formatImaAdpcm,+ HwParams.formatMpeg,+ HwParams.formatGsm,+ HwParams.formatSpecial,+ HwParams.formatS243le,+ HwParams.formatS243be,+ HwParams.formatU243le,+ HwParams.formatU243be,+ HwParams.formatS203le,+ HwParams.formatS203be,+ HwParams.formatU203le,+ HwParams.formatU203be,+ HwParams.formatS183le,+ HwParams.formatS183be,+ HwParams.formatU183le,+ HwParams.formatU183be,+ HwParams.formatS16,+ HwParams.formatU16,+ HwParams.formatS24,+ HwParams.formatU24,+ HwParams.formatS32,+ HwParams.formatU32,+ HwParams.formatFloat,+ HwParams.formatFloat64,+ HwParams.formatIec958Subframe,++ HwParams.Subformat,+-}++ -- * Primitive accessors to hardware parameters+ HwParams.canMmapSampleResolution,+ HwParams.isDouble,+ HwParams.isBatch,+ HwParams.isBlockTransfer,+ HwParams.canOverrange,+ HwParams.canPause,+ HwParams.canResume,+ HwParams.isHalfDuplex,+ HwParams.isJointDuplex,+ HwParams.canSyncStart,+ HwParams.getRateNumden,+ HwParams.getSbits,+ HwParams.getFifoSize,+{- integrated in 'with'+ HwParams.getAccess,+ HwParams.testAccess,+ HwParams.setAccess,+ HwParams.setAccessFirst,+ HwParams.setAccessLast,+ HwParams.getFormat,+ HwParams.testFormat,+ HwParams.setFormat,+ HwParams.setFormatFirst,+ HwParams.setFormatLast,+-}+{- don't know how to use this reasonably+ HwParams.getSubformat,+ HwParams.testSubformat,+ HwParams.setSubformat,+ HwParams.setSubformatFirst,+ HwParams.setSubformatLast,+-}+ HwParams.getChannels,+ HwParams.getChannelsMin,+ HwParams.getChannelsMax,+ HwParams.testChannels,+ setChannels,+ setChannelsMin,+ setChannelsMax,+ setChannelsMinmax,+ setChannelsNear,+ setChannelsFirst,+ setChannelsLast,+ HwParams.getRate,+ HwParams.getRateMin,+ HwParams.getRateMax,+ HwParams.testRate,+ HwParams.setRate,+ HwParams.setRateMin,+ HwParams.setRateMax,+ HwParams.setRateMinmax,+ HwParams.setRateNear,+ HwParams.setRateFirst,+ HwParams.setRateLast,+ HwParams.setRateResample,+ HwParams.getRateResample,+ HwParams.setExportBuffer,+ HwParams.getExportBuffer,+ HwParams.getPeriodTime,+ HwParams.getPeriodTimeMin,+ HwParams.getPeriodTimeMax,+ HwParams.testPeriodTime,+ HwParams.setPeriodTime,+ HwParams.setPeriodTimeMin,+ HwParams.setPeriodTimeMax,+ HwParams.setPeriodTimeMinmax,+ HwParams.setPeriodTimeNear,+ HwParams.setPeriodTimeFirst,+ HwParams.setPeriodTimeLast,+ HwParams.getPeriodSize,+ HwParams.getPeriodSizeMin,+ HwParams.getPeriodSizeMax,+ HwParams.testPeriodSize,+ HwParams.setPeriodSize,+ HwParams.setPeriodSizeMin,+ HwParams.setPeriodSizeMax,+ HwParams.setPeriodSizeMinmax,+ HwParams.setPeriodSizeNear,+ HwParams.setPeriodSizeFirst,+ HwParams.setPeriodSizeLast,+ HwParams.setPeriodSizeInteger,+ HwParams.getPeriods,+ HwParams.getPeriodsMin,+ HwParams.getPeriodsMax,+ HwParams.testPeriods,+ HwParams.setPeriods,+ HwParams.setPeriodsMin,+ HwParams.setPeriodsMax,+ HwParams.setPeriodsMinmax,+ HwParams.setPeriodsNear,+ HwParams.setPeriodsFirst,+ HwParams.setPeriodsLast,+ HwParams.setPeriodsInteger,+ HwParams.getBufferTime,+ HwParams.getBufferTimeMin,+ HwParams.getBufferTimeMax,+ HwParams.testBufferTime,+ HwParams.setBufferTime,+ HwParams.setBufferTimeMin,+ HwParams.setBufferTimeMax,+ HwParams.setBufferTimeMinmax,+ HwParams.setBufferTimeNear,+ HwParams.setBufferTimeFirst,+ HwParams.setBufferTimeLast,+ HwParams.getBufferSize,+ HwParams.getBufferSizeMin,+ HwParams.getBufferSizeMax,+ HwParams.testBufferSize,+ HwParams.setBufferSize,+ HwParams.setBufferSizeMin,+ HwParams.setBufferSizeMax,+ HwParams.setBufferSizeMinmax,+ HwParams.setBufferSizeNear,+ HwParams.setBufferSizeFirst,+ HwParams.setBufferSizeLast,+ HwParams.getTickTime,+ HwParams.getTickTimeMin,+ HwParams.getTickTimeMax,+ HwParams.testTickTime,+ HwParams.setTickTime,+ HwParams.setTickTimeMin,+ HwParams.setTickTimeMax,+ HwParams.setTickTimeMinmax,+ HwParams.setTickTimeNear,+ HwParams.setTickTimeFirst,+ HwParams.setTickTimeLast,+ HwParams.getMinAlign,++ -- * Complex hardware parameter configuration+ setRateBufferTime,+ ) where++import qualified Sound.ALSA.PCM.Core.HwParams as HwParams+import Sound.ALSA.PCM.Core.HwParams (T, )+import Sound.ALSA.PCM.Core.Handle+ (SampleFreq, Time, Size, Interleaved, Noninterleaved, )++import Data.Word (Word, )+++{-+Our approach cannot assert, that setChannels is called.+Is this necessary, at all?+If yes, setChannel accessors could return a secret value,+that must be passed to 'writen' in order to prove,+that setChannel was called.+-}++{- |+For non-interleaved access the number of channels must be set manually.+It can be chosen at runtime,+but the compiler cannot check whether the number of allocated channels+matches the one in 'readn' and 'writen'.++In interleaved access the number of channels is derived from the type+and must not be set manually.+The number is static+but the compiler checks consistency with 'readi' and 'writei'.+-}+setChannels :: Word -> T Noninterleaved y ()+setChannels = HwParams.setChannels++setChannelsMin :: Word -> T Noninterleaved y Word+setChannelsMin = HwParams.setChannelsMin++setChannelsMax :: Word -> T Noninterleaved y Word+setChannelsMax = HwParams.setChannelsMax++setChannelsMinmax :: Word -> Word -> T Noninterleaved y (Word, Word)+setChannelsMinmax = HwParams.setChannelsMinmax++setChannelsNear :: Word -> T Noninterleaved y Word+setChannelsNear = HwParams.setChannelsNear++setChannelsFirst :: Word -> T Noninterleaved y Word+setChannelsFirst = HwParams.setChannelsFirst++setChannelsLast :: Word -> T Noninterleaved y Word+setChannelsLast = HwParams.setChannelsLast++++setRateBufferTime ::+ SampleFreq -- ^ sample frequency+ -> Time -- ^ buffer time+ -> Time -- ^ period time+ -> T Interleaved y (Size,Size)+ -- ^ (bufferSize,periodSize)+setRateBufferTime rate bufferTime periodTime = do+ HwParams.setRate rate EQ+ _ <- HwParams.setBufferTimeNear bufferTime EQ+ bufferSize <- HwParams.getBufferSize+ _ <- HwParams.setPeriodTimeNear periodTime EQ+ (periodSize,_) <- HwParams.getPeriodSize+ return (bufferSize,periodSize)
+ src/Sound/ALSA/PCM/Parameters/Software.hs view
@@ -0,0 +1,37 @@+module Sound.ALSA.PCM.Parameters.Software (+ -- * Types+ SwParams.T, Size,+ TimestampMode, timestampNone, timestampMmap,++ -- * Primitive accessors to software parameters+ getAvailMin, setAvailMin,+ getSilenceSize, setSilenceSize,+ getSilenceThreshold, setSilenceThreshold,+ getSleepMin, setSleepMin,+ getStartThreshold, setStartThreshold,+ getStopThreshold, setStopThreshold,+ getTimestampMode, setTimestampMode,+ getXferAlign, setXferAlign,++ -- * Complex software parameter configuration+ setBufferSize,+ ) where++import Sound.ALSA.PCM.Core.SwParams as SwParams+import Sound.ALSA.PCM.Core.Handle (Size, )+++setBufferSize ::+ Size -- ^ buffer size+ -> Size -- ^ period size+ -> SwParams.T i y ()+setBufferSize _bufferSize periodSize = do+ -- let startThreshold =+ -- (setBufferSize `div` periodSize) * periodSize+ -- setStartThreshold startThreshold+ setStartThreshold 0+ setAvailMin $ fromIntegral periodSize+ setXferAlign 1+ -- pad buffer with silence when needed+ -- setSilenceSize periodSize+ -- setSilenceThreshold periodSize