module System.Hardware.Arduino.Parts.Piezo(
Piezo, speaker
, Note(..), Duration(..)
, playNote, rest, silence
, playNotes
) where
import Data.Bits (shiftR, (.&.))
import Data.Maybe (fromMaybe)
import System.Hardware.Arduino
import System.Hardware.Arduino.Comm
import System.Hardware.Arduino.Data
data Piezo = Piezo { piezoPin :: IPin
, tempo :: Int
}
speaker :: Int
-> Pin
-> Arduino Piezo
speaker t p = do debug $ "Attaching speaker on pin: " ++ show p
setPinMode p PWM
(ip, _) <- convertAndCheckPin "Piezo.speaker" p PWM
return Piezo { piezoPin = ip, tempo = t }
data Note = A | B | C | D | E | F | G | R deriving (Eq, Show)
data Duration = Whole | Half | Quarter | Eight deriving (Eq, Show)
frequency :: Note -> Int
frequency n = fromMaybe 0 (n `lookup` fs)
where fs = [(A, 440), (B, 493), (C, 261), (D, 294), (E, 329), (F, 349), (G, 392), (R, 0)]
interval :: Piezo -> Duration -> Int
interval p Whole = 8 * interval p Eight
interval p Half = 4 * interval p Eight
interval p Quarter = 2 * interval p Eight
interval p Eight = tempo p
silence :: Piezo -> Arduino ()
silence (Piezo p _) = send $ AnalogPinWrite p 0 0
setNote :: Piezo -> Note -> Arduino ()
setNote (Piezo p _) n = send $ AnalogPinWrite p (fromIntegral lsb) (fromIntegral msb)
where f = frequency n
lsb = f .&. 0x7f
msb = (f `shiftR` 7) .&. 0x7f
playNote :: Piezo -> (Note, Duration) -> Arduino ()
playNote pz (n, d) = do setNote pz n
delay (interval pz d)
silence pz
playNotes :: Piezo -> [(Note, Duration)] -> Arduino ()
playNotes pz = go
where go [] = silence pz
go (nd@(_, d):r) = do playNote pz nd
delay (interval pz d `div` 3)
go r
rest :: Piezo -> Duration -> Arduino ()
rest pz d = delay (interval pz d)