{-# LANGUAGE NoImplicitPrelude #-}{- |
Copyright : (c) Henning Thielemann 2008
License : GPL
Maintainer : synthesizer@henning-thielemann.de
Stability : provisional
Portability : requires multi-parameter type classes
-}moduleSynthesizer.Dimensional.RateAmplitude.Noise(white,whiteBandEnergy,randomPeeks,whiteGen,whiteBandEnergyGen,randomPeeksGen,)whereimportqualifiedSynthesizer.State.NoiseCustomasNoiseimportqualifiedSynthesizer.State.SignalasSigimportqualifiedSynthesizer.RandomKnuthasKnuthimportqualifiedSynthesizer.Dimensional.RateAmplitude.SignalasSigAimportqualifiedSynthesizer.Dimensional.Rate.DiracasDiracimportqualifiedSynthesizer.Dimensional.ProcessasProcimportSynthesizer.Dimensional.Process(($#),)importqualifiedNumber.DimensionTermasDNimportqualifiedAlgebra.DimensionTermasDimimportNumber.DimensionTerm((&*&))importqualifiedAlgebra.AlgebraicasAlgebraicimportqualifiedAlgebra.FieldasFieldimportqualifiedAlgebra.RingasRingimportSystem.Random(Random,RandomGen,mkStdGen)importNumericPreludeimportPreludeBaseasP{-# INLINE white #-}{- The Field.C constraint could be replaced by Ring.C
if Noise instead of faster NoiseCustom would be used -}white::(Field.Cyv,Randomyv,Algebraic.Cq,Dim.Cu,Dim.Cv)=>DN.T(Dim.Recipu)q{-^ width of the frequency band -}->DN.Tvq{-^ volume caused by the given frequency band -}->Proc.Tsuq(SigA.Rsvqyv){-^ noise -}white=-- FIXME: there was a bug in GHC-6.4's standard random generator where genRange returned minBound::Int as lower bound but actually generated numbers were always positive-- this is fixed in GHC-6.6 and thus the standard generator can be usedwhiteGen(Knuth.cons6746)-- whiteGen (mkStdGen 6746){-# INLINE whiteGen #-}whiteGen::(Field.Cyv,Randomyv,RandomGeng,Algebraic.Cq,Dim.Cu,Dim.Cv)=>g{-^ random generator, can be used to choose a seed -}->DN.T(Dim.Recipu)q{-^ width of the frequency band -}->DN.Tvq{-^ volume caused by the given frequency band -}->Proc.Tsuq(SigA.Rsvqyv){-^ noise -}whiteGengenbandWidthvolume=dobw<-SigA.toFrequencyScalarbandWidthreturn$SigA.fromSamples(DN.scale(sqrt$3/bw)volume)(Noise.whiteGengen){-# INLINE whiteBandEnergy #-}whiteBandEnergy::(Field.Cyv,Randomyv,Algebraic.Cq,Dim.Cu,Dim.Cv)=>DN.T(Dim.Mulu(Dim.Sqrv))q{-^ energy per frequency band -}->Proc.Tsuq(SigA.Rsvqyv){-^ noise -}whiteBandEnergy=whiteBandEnergyGen(mkStdGen6746){-# INLINE whiteBandEnergyGen #-}whiteBandEnergyGen::(Field.Cyv,Randomyv,RandomGeng,Algebraic.Cq,Dim.Cu,Dim.Cv)=>g{-^ random generator, can be used to choose a seed -}->DN.T(Dim.Mulu(Dim.Sqrv))q{-^ energy per frequency band -}->Proc.Tsuq(SigA.Rsvqyv){-^ noise -}whiteBandEnergyGengenenergy=dorate<-Proc.getSampleRatereturn$SigA.fromSamples(DN.sqrt$DN.scale3$DN.rewriteDimension(Dim.identityLeft.Dim.applyLeftMulDim.cancelLeft.Dim.associateLeft)$rate&*&energy)(Noise.whiteGengen){-
The Field.C q constraint could be lifted to Ring.C
if we would use direct division instead of toFrequencyScalar.
-}{-# INLINE randomPeeks #-}randomPeeks::(Field.Cq,Randomq,Ordq,Dim.Cu)=>Proc.Tsuq(SigA.Rs(Dim.Recipu)qq{- v instantaneous densities (frequency),
@p@ means that there is about one peak
in the time range of @1\/p@. -}->SigA.Rs(Dim.Recipu)qq){- ^ Every occurrence is represented by a peak of area 1.
If you smooth the input and the output signal to the same degree
they should be rather similar. -}randomPeeks=randomPeeksGen(mkStdGen876){-# INLINE randomPeeksGen #-}randomPeeksGen::(Field.Cq,Randomq,Ordq,Dim.Cu,RandomGeng)=>g{- ^ random generator, can be used to choose a seed -}->Proc.Tsuq(SigA.Rs(Dim.Recipu)qq{- v momentary densities (frequency),
@p@ means that there is about one peak
in the time range of @1\/p@. -}->SigA.Rs(Dim.Recipu)qq){- ^ Every occurrence is represented by a peak of area 1. -}randomPeeksGeng=Proc.withParam$\dens->dofreq<-SigA.toFrequencyScalar(SigA.amplitudedens)Dirac.toAmplitudeSignal$#(Dirac.Cons$Sig.zipWith(<)(Noise.randomRs(0,recipfreq)g)(SigA.samplesdens))