Skip to content

Instantly share code, notes, and snippets.

@leftaroundabout
Last active September 2, 2017 13:18
Embed
What would you like to do?
Spectrum view of the effect nonlinear distortion has on various sound signals
import Numeric.FFT.Vector.Invertible
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Generic as GA
import Data.Complex (magnitude)
import Data.Function ((&))
import Graphics.Dynamic.Plot.R2
main :: IO ()
main = do
plotWindow . distortionCompare $ sineSig 163 ^+^ sineSig 308
plotWindow . distortionCompare $ stringSig 100
plotWindow . distortionCompare $ stringSig (note "A2") ^+^ stringSig (note "E3")
plotWindow . distortionCompare $ stringSig (note "C3") ^+^ stringSig (note "E3")
plotWindow . distortionCompare $ stringSig (note "C3") ^+^ stringSig (5/4*note "C3")
plotWindow . distortionCompare $ stringSig (note "B2") ^+^ stringSig (note "F3")
plotWindow . distortionCompare $ stringSig (note "B2") ^+^ stringSig (7/5*note "B2")
return ()
type ℝ = Double
type Signal = Vector ℝ
type Freq = ℝ
signalPlot, spectrumPlot :: Signal -> DynamicPlottable
signalPlot sig = lineSegPlot
$ zip [0,1/fromIntegral n..] (GA.toList sig)
where n = GA.length sig
spectrumPlot sig = lineSegPlot
$ zip [0..800] ((2/fromIntegral n*) . magnitude <$> GA.toList spectrum)
where spectrum = run dftR2C sig
n = GA.length sig
distortion :: Signal -> Vector ℝ
distortion = GA.map (tanh . (*4))
distortionCompare :: Signal -> [DynamicPlottable]
distortionCompare sig
= [ spectrumPlot sig & legendName "Original"
, spectrumPlot (distortion sig) & legendName "Distorted" ]
sineSig :: Freq -> Signal
sineSig ν = GA.generate n $ \i
-> sin (2 * pi * ν*fromIntegral i/fromIntegral n) / 2
where n = samplingFreq
stringSig :: Freq -> Signal
stringSig ν = GA.generate n $ \i ->
tan (sin (2 * pi * ν*fromIntegral i/fromIntegral n) * 1.3) / 3
+ tan (sin (4 * pi * ν*fromIntegral i/fromIntegral n)) / 2
where n = samplingFreq
samplingFreq :: Int
samplingFreq = 44100
note :: String -> Freq
note (nn:octv) = 440 * 2**(read octv - 4 + fromIntegral pitchClass/12)
where pitchClass = round $ fromIntegral ((fromEnum nn - fromEnum 'C')`mod`7 - 1) * 12/7 - 7
infixl 6 ^+^
(^+^) :: Signal -> Signal -> Signal
(^+^) = GA.zipWith (+)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment