pitchtrack (empty) → 0.1.0.0
raw patch · 9 files changed
+259/−0 lines, 9 filesdep +basedep +bytestringdep +dywapitchtracksetup-changedbinary-added
Dependencies added: base, bytestring, dywapitchtrack, hspec, pipes, pipes-bytestring, process, transformers
Files
- LICENSE +21/−0
- Setup.hs +2/−0
- pitchtrack.cabal +75/−0
- src/PitchTrack.hs +9/−0
- src/PitchTrack/Pipes.hs +41/−0
- src/PitchTrack/Track.hs +88/−0
- test/PitchTrack/TrackSpec.hs +22/−0
- test/Spec.hs +1/−0
- test/files/a4-5sec.raw binary
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2015 Lorenzo Tabacchini++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ pitchtrack.cabal view
@@ -0,0 +1,75 @@+name: pitchtrack+version: 0.1.0.0+cabal-version: >=1.10+build-type: Simple+license: MIT+license-file: LICENSE+copyright: (c) 2015 Lorenzo Tabacchini+maintainer: lortabac@gmx.com+bug-reports: https://github.com/lortabac/pitchtrack/issues+synopsis: Pitch tracking library+description:+ Pitch tracking library, based on <http://www.schmittmachine.com/dywapitchtrack.html dywapitchtrack>.+ .+ See the "PitchTrack" module for an easy, "ready to use" interface,+ or "PitchTrack.Pipes" for Pipes-based components, if you need more flexibility.+ .+ Note that because all parameters are hard-coded into the C library,+ you are limited to the following audio configuration:+ .+ * raw (headerless) format+ .+ * a sampling rate of 44100Hz,+ .+ * a sample size of @sizeof(double)@+ .+ * floating-point encoding+ .+ * one channel (mono)+category: Sound+author: Lorenzo Tabacchini+tested-with: GHC >=7.10+extra-source-files:+ test/files/a4-5sec.raw++source-repository head+ type: git+ location: https://github.com/lortabac/pitchtrack.git++library+ exposed-modules:+ PitchTrack+ PitchTrack.Track+ PitchTrack.Pipes+ build-depends:+ base ==4.8.*,+ bytestring >=0.10.6.0 && <0.11,+ dywapitchtrack >=0.1.0.0 && <0.2,+ pipes >=4.1.6 && <4.2,+ pipes-bytestring >=2.1.1 && <2.2,+ process >=1.2.3.0 && <1.3,+ transformers >=0.4.2.0 && <0.5+ default-language: Haskell2010+ hs-source-dirs: src+ ghc-options: -Wall++test-suite spec+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ build-depends:+ base ==4.8.*,+ bytestring >=0.10.6.0 && <0.11,+ dywapitchtrack >=0.1.0.0 && <0.2,+ hspec >=2.2.0 && <2.3,+ pipes >=4.1.6 && <4.2,+ pipes-bytestring >=2.1.1 && <2.2,+ process >=1.2.3.0 && <1.3,+ transformers >=0.4.2.0 && <0.5+ default-language: Haskell2010+ hs-source-dirs: test src+ other-modules:+ PitchTrack+ PitchTrack.Track+ PitchTrack.Pipes+ PitchTrack.TrackSpec+ ghc-options: -Wall
+ src/PitchTrack.hs view
@@ -0,0 +1,9 @@+module PitchTrack (+-- * Re-exported modules+ module PitchTrack.Track+-- * Utilities+ , neededSampleNum+ ) where++import DywaPitchTrack (neededSampleNum)+import PitchTrack.Track
+ src/PitchTrack/Pipes.hs view
@@ -0,0 +1,41 @@+module PitchTrack.Pipes (+ samplesFromHandle+ , samplesFromLBS+ , forPitch+ , forPitch_+ , getPitch+ , printPitch+ ) where++import DywaPitchTrack++import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy as LBS+import Pipes+import qualified Pipes.ByteString as PB+import qualified Pipes.Prelude as P+import System.IO++-- | Stream chunks of a fixed number of samples from a handle+samplesFromHandle :: Int -> Handle -> Producer ByteString PitchTrack ()+samplesFromHandle sampleNum = PB.hGet (sampleNum * sampleSize)++-- | Stream chunks of a fixed number of samples from a lazy 'LBS.ByteString'+samplesFromLBS :: Int -> LBS.ByteString -> Producer ByteString PitchTrack ()+samplesFromLBS sampleNum lbs = PB.fromLazy lbs >-> PB.take sampleNum++-- | Apply a function to each pitch+forPitch :: Producer ByteString PitchTrack () -> (Double -> PitchTrack a) -> Producer a PitchTrack ()+forPitch samplesProducer f = getPitch samplesProducer >-> P.mapM f++-- | Consume all pitches, applying a function to each one+forPitch_ :: Producer ByteString PitchTrack () -> (Double -> PitchTrack ()) -> Effect PitchTrack ()+forPitch_ samplesProducer f = getPitch samplesProducer >-> P.mapM_ f++-- | Stream computed pitches+getPitch :: Producer ByteString PitchTrack () -> Producer Double PitchTrack ()+getPitch samplesProducer = samplesProducer >-> P.mapM computePitch++-- | Print all pitches+printPitch :: Producer ByteString PitchTrack () -> Effect PitchTrack ()+printPitch samplesProducer = getPitch samplesProducer >-> P.print
+ src/PitchTrack/Track.hs view
@@ -0,0 +1,88 @@+{- |+This module provides a high-level interface for the most common cases.++The default number of samples used for each computation is 2048,+which should be enough if you never go below 65Hz.+If you need a different number, you should use the functions whose name ends with @N@,+which take the number of samples as a first parameter.+-}+module PitchTrack.Track (+-- * Reading from a file+ trackFile+ , trackFileN+ , trackFileToList+-- * Reading from stdin+ , trackStdin+ , trackStdinN+-- * Reading from a handle+ , trackHandle+ , trackHandleN+-- * Reading from a lazy 'LBS.ByteString'+ , trackLBS+ , trackLBSN+-- * Other definitions+ , defaultSampleNum+ ) where++import DywaPitchTrack+import PitchTrack.Pipes++import qualified Data.ByteString.Lazy as LBS+import Pipes+import qualified Pipes.Prelude as P+import System.IO++-- | Track a file and apply a function to each computed pitch+--+-- >>> trackFile "a440.raw" $ \pitch -> liftIO $ putStr (show pitch ++ ",")+-- 440.0,440.0,440.0,440.0,440.0,440.0,440.0,440.0,440.0,440.0,440.0,440.0,+trackFile :: FilePath -> (Double -> PitchTrack ()) -> IO ()+trackFile = trackFileN defaultSampleNum++-- | Same as 'trackFile', but takes the number of samples as a first parameter+trackFileN :: Int -> FilePath -> (Double -> PitchTrack ()) -> IO ()+trackFileN sampleNum file f = withFileR file $ \ h->+ trackHandleN sampleNum h f++-- | Same as 'trackFile' but reads from 'System.IO.stdin' instead of a file+trackStdin :: (Double -> PitchTrack ()) -> IO ()+trackStdin = trackStdinN defaultSampleNum++-- | Same as 'trackStdin', but takes the number of samples as a first parameter+trackStdinN :: Int -> (Double -> PitchTrack ()) -> IO ()+trackStdinN sampleNum = trackHandleN sampleNum stdin++-- | Same as 'trackFile' but reads from a handle instead of a file+trackHandle :: Handle -> (Double -> PitchTrack ()) -> IO ()+trackHandle = trackHandleN defaultSampleNum++-- | Same as 'trackHandle', but takes the number of samples as a first parameter+trackHandleN :: Int -> Handle -> (Double -> PitchTrack ()) -> IO ()+trackHandleN sampleNum h f = runPitchTrack sampleNum $+ runEffect $ forPitch_ (samplesFromHandle sampleNum h) f++-- | Track a lazy 'LBS.ByteString' and apply a function to each computed pitch+trackLBS :: LBS.ByteString -> (Double -> PitchTrack ()) -> IO ()+trackLBS = trackLBSN defaultSampleNum++-- | Same as 'trackLBS', but takes the number of samples as a first parameter+trackLBSN :: Int -> LBS.ByteString -> (Double -> PitchTrack ()) -> IO ()+trackLBSN sampleNum lbs f = runPitchTrack sampleNum $+ runEffect $ forPitch_ (samplesFromLBS sampleNum lbs) f++-- | Track a file and return a list of all the computed pitches+--+-- Note: the whole list is loaded into memory+trackFileToList :: FilePath -> IO [Double]+trackFileToList = trackFileToListN defaultSampleNum++trackFileToListN :: Int -> FilePath -> IO [Double]+trackFileToListN sampleNum file = withFileR file $ \h ->+ runPitchTrack sampleNum $ P.toListM $ forPitch (samplesFromHandle sampleNum h) return++-- | The default number of samples used for each computation (2048)+defaultSampleNum :: Int+defaultSampleNum = 2048++withFileR :: FilePath -> (Handle -> IO r) -> IO r+withFileR file = withFile file ReadMode
+ test/PitchTrack/TrackSpec.hs view
@@ -0,0 +1,22 @@+module PitchTrack.TrackSpec (spec) where++import PitchTrack.Track++import Control.Monad.IO.Class+import Test.Hspec++spec :: Spec+spec = describe "trackFile" $ do+ it "should find the right frequency (±1Hz)" $ do+ pitches <- liftIO $ trackFileToList a4File+ all (\p -> abs (440.0 - p) < 1) (init pitches) `shouldBe` True++ it "should compute the right number of pitches" $ do+ pitches <- liftIO $ trackFileToList a4File+ length pitches `shouldBe` ceiling (sampleRate * 5 / fromIntegral defaultSampleNum)++a4File :: FilePath+a4File = "test/files/a4-5sec.raw"++sampleRate :: Double+sampleRate = 44100
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/files/a4-5sec.raw view
binary file changed (absent → 1764000 bytes)