From 9b617ee846dc17ff35481171479f03f23a4ddf5f Mon Sep 17 00:00:00 2001 From: Bernardo Barros Date: Wed, 31 Jan 2024 03:16:56 -0500 Subject: [PATCH] Add Pitch.Hz module for working with musical pitches in Hertz --- haskMus.cabal | 1 + src/Pitch/Hz.hs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/Pitch/Hz.hs diff --git a/haskMus.cabal b/haskMus.cabal index 2fe27b4..626b4e2 100644 --- a/haskMus.cabal +++ b/haskMus.cabal @@ -29,6 +29,7 @@ library Pitch.Parser Pitch.Pitch Pitch.QuasiQuoter + Pitch.Hz Rtm.Common Rtm.Parser Rtm.QuasiQuoter diff --git a/src/Pitch/Hz.hs b/src/Pitch/Hz.hs new file mode 100644 index 0000000..05757e9 --- /dev/null +++ b/src/Pitch/Hz.hs @@ -0,0 +1,33 @@ +module Pitch.Hz where + +-- | The Pitch.Hz module provides types and functions to work with musical pitches in terms of semitones and Hertz. + +-- `newtype` wrappers for `Semitone` and `Hz` provide type safety. +newtype Semitone = Semitone {unSemitone :: Double} deriving (Show, Eq, Num, Ord) +newtype Hz = Hz {unHz :: Double} deriving (Show, Eq, Num, Ord) + +-- Standard pitch (A4) definition in Hertz. +pitchStandard :: Hz +pitchStandard = Hz 440.0 + +-- Convert a `Semitone` or `Double` representing semitones to `Hz`. +-- Works for both integral and fractional semitones. +semitoneToHz :: Double -> Hz +semitoneToHz n = pitchStandard * Hz (2 ** (n / 12.0)) + +-- Convert a frequency in `Hz` to its equivalent in semitones relative to `pitchStandard`. +-- Calculated using the logarithm base 2. +hzToDouble :: Hz -> Double +hzToDouble (Hz hz) = 12.0 * logBase 2 (hz / unHz pitchStandard) + +-- Use `hzToDouble` to convert Hz to `Semitone`. +hzToSemitone :: Hz -> Semitone +hzToSemitone = Semitone . hzToDouble + +-- Directly retrieve the underlying `Double` from a `Semitone`. +semitoneToDouble :: Semitone -> Double +semitoneToDouble (Semitone n) = n + +-- Wrap a `Double` as a `Semitone`. +doubleToSemitone :: Double -> Semitone +doubleToSemitone = Semitone