------------------------------------------------------------------------------- |-- Module : Data.Audio-- Copyright : George Giorgidze-- License : BSD3-- -- Maintainer : George Giorgidze <http://cs.nott.ac.uk/~ggg/>-- Stability : Experimental-- Portability : Portable---- General purpose data type for representing an audio data.-------------------------------------------------------------------------------{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}{-# OPTIONS_GHC -fno-warn-orphans #-}moduleData.Audio(Sample,Audio(..),SampleData,SampleMode(..),sampleType,sampleNumber,convert,parseSampleData,buildSampleData,Audible,toSample,fromSample)whereimportData.ArbitraryimportData.ByteString.ParserimportData.ByteString.BuilderimportData.WordimportData.IntimportData.Array.DiffimportData.ListimportData.MonoidimportTest.QuickChecktypeSample=DoubleclassAudibleawheretoSample::a->SamplefromSample::Sample->a-- It is required that sampleNummer `mod` channelNumber == 0dataAudioa=Audio{sampleRate::Int,channelNumber::Int,sampleData::SampleDataa}instance(Eqa,IArrayDiffUArraya)=>Eq(Audioa)wherea1==a2=and[sampleRatea1==sampleRatea2,channelNumbera1==channelNumbera2,assocs(sampleDataa1)==assocs(sampleDataa2)]instance(Eqe,Ixi,IArray(IOToDiffArraya)e)=>Eq(IOToDiffArrayaie)wherea1==a2=assocsa1==assocsa2typeSampleDataa=DiffUArrayIntainstance(Showa,IArrayDiffUArraya)=>Show(Audioa)whereshowa="Sample Rate: "++(show$sampleRatea)++"\n"++"Channel Number: "++(show$channelNumbera)++"\n"++"Sample Data Array Bounds: "++(show$bounds$sampleDataa)instance(Arbitrarya,IArrayDiffUArraya)=>Arbitrary(Audioa)wherearbitrary=dosr<-choose(minBound,maxBound)cn<-choose(1,64)sn<-choose(1,1024)>>=return.(fromIntegralcn*)sd<-arrayGensnreturn$!Audiosrcnsdcoarbitrary=undefinedsampleNumber::(IArrayDiffUArraya)=>SampleDataa->IntsampleNumbersd=(snd$boundssd)+1sampleType::(IArrayDiffUArraya)=>SampleDataa->asampleTypesd=undefined`asTypeOf`(sd!0)convert::(Audiblea,Audibleb,IArrayDiffUArraya,IArrayDiffUArrayb)=>SampleDataa->SampleDatabconvertsd=amap(fromSample.toSample)sd-- It is very important to implement this parser efficiently-- It seems that DiffUArray leaks memmory.-- When I am profilling, profiler shows that function retains memmory which is-- a same size as an array created by parser.-- However when I am running compiled binary almoust twice as much memmory is-- consumed from the system, this behaviour seems very strange to me.-- Updating an array every time when sample is parsed-- results in a poor preformance that is why currently I am using-- list buffer and apdating array with 64 samples at once.parseSampleData::(IArrayDiffUArraya)=>Int->Parsera->Parser(SampleDataa)parseSampleDatasnp=pAux0(array(0,sn-1)[])[]wherepAuxiaccbuf|(i==sn)=return$!acc//bufpAuxiaccbuf|modi64==0=dos<-pletacc'=seqs$acc//((i,s):buf)inseqacc'$pAux(i+1)acc'[]pAuxiaccbuf=dos<-pseqs$pAux(i+1)acc((i,s):buf)buildSampleData::(IArrayDiffUArraya)=>(a->Builder)->SampleDataa->BuilderbuildSampleDatabsd=mconcat$mapb$elemssdinstanceAudibleInt8wheretoSamplea=(fromIntegrala)/(2**7)fromSamples=round$s*(2**7)instanceAudibleInt16wheretoSamplea=(fromIntegrala)/(2**15)fromSamples=round$s*(2**15)instanceAudibleInt32wheretoSamplea=(fromIntegrala)/(2**31)fromSamples=round$s*(2**31)instanceAudibleInt64wheretoSamplea=(fromIntegrala)/(2**63)fromSamples=round$s*(2**63)instanceAudibleWord8wheretoSamplea=(fromIntegrala)/(2**7)-1.0fromSamples=round$(s+1.0)*(2**7)instanceAudibleWord16wheretoSamplea=(fromIntegrala)/(2**15)-1.0fromSamples=round$(s+1.0)*(2**15)instanceAudibleWord32wheretoSamplea=(fromIntegrala)/(2**31)-1.0fromSamples=round$(s+1.0)*(2**31)instanceAudibleWord64wheretoSamplea=(fromIntegrala)/(2**63)-1.0fromSamples=round$(s+1.0)*(2**63)instanceAudibleFloatwheretoSample=realToFracfromSample=realToFracinstanceAudibleDoublewheretoSample=idfromSample=iddataSampleMode=NoLoop|ContLoop|PressLoopderiving(Eq,Show)instanceArbitrarySampleModewherearbitrary=oneof[returnNoLoop,returnContLoop,returnPressLoop]coarbitrary=undefined