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 { Piezo -> IPin
piezoPin :: IPin
, Piezo -> Int
tempo :: Int
}
speaker :: Int
-> Pin
-> Arduino Piezo
speaker :: Int -> Pin -> Arduino Piezo
speaker Int
t Pin
p = do String -> Arduino ()
debug (String -> Arduino ()) -> String -> Arduino ()
forall a b. (a -> b) -> a -> b
$ String
"Attaching speaker on pin: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Pin -> String
forall a. Show a => a -> String
show Pin
p
Pin -> PinMode -> Arduino ()
setPinMode Pin
p PinMode
PWM
(ip, _) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"Piezo.speaker" Pin
p PinMode
PWM
return Piezo { piezoPin = ip, tempo = t }
data Note = A | B | C | D | E | F | G | R deriving (Note -> Note -> Bool
(Note -> Note -> Bool) -> (Note -> Note -> Bool) -> Eq Note
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Note -> Note -> Bool
== :: Note -> Note -> Bool
$c/= :: Note -> Note -> Bool
/= :: Note -> Note -> Bool
Eq, Int -> Note -> String -> String
[Note] -> String -> String
Note -> String
(Int -> Note -> String -> String)
-> (Note -> String) -> ([Note] -> String -> String) -> Show Note
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> Note -> String -> String
showsPrec :: Int -> Note -> String -> String
$cshow :: Note -> String
show :: Note -> String
$cshowList :: [Note] -> String -> String
showList :: [Note] -> String -> String
Show)
data Duration = Whole | Half | Quarter | Eight deriving (Duration -> Duration -> Bool
(Duration -> Duration -> Bool)
-> (Duration -> Duration -> Bool) -> Eq Duration
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Duration -> Duration -> Bool
== :: Duration -> Duration -> Bool
$c/= :: Duration -> Duration -> Bool
/= :: Duration -> Duration -> Bool
Eq, Int -> Duration -> String -> String
[Duration] -> String -> String
Duration -> String
(Int -> Duration -> String -> String)
-> (Duration -> String)
-> ([Duration] -> String -> String)
-> Show Duration
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> Duration -> String -> String
showsPrec :: Int -> Duration -> String -> String
$cshow :: Duration -> String
show :: Duration -> String
$cshowList :: [Duration] -> String -> String
showList :: [Duration] -> String -> String
Show)
frequency :: Note -> Int
frequency :: Note -> Int
frequency Note
n = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
0 (Note
n Note -> [(Note, Int)] -> Maybe Int
forall a b. Eq a => a -> [(a, b)] -> Maybe b
`lookup` [(Note, Int)]
fs)
where fs :: [(Note, Int)]
fs = [(Note
A, Int
440), (Note
B, Int
493), (Note
C, Int
261), (Note
D, Int
294), (Note
E, Int
329), (Note
F, Int
349), (Note
G, Int
392), (Note
R, Int
0)]
interval :: Piezo -> Duration -> Int
interval :: Piezo -> Duration -> Int
interval Piezo
p Duration
Whole = Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Piezo -> Duration -> Int
interval Piezo
p Duration
Eight
interval Piezo
p Duration
Half = Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Piezo -> Duration -> Int
interval Piezo
p Duration
Eight
interval Piezo
p Duration
Quarter = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Piezo -> Duration -> Int
interval Piezo
p Duration
Eight
interval Piezo
p Duration
Eight = Piezo -> Int
tempo Piezo
p
silence :: Piezo -> Arduino ()
silence :: Piezo -> Arduino ()
silence (Piezo IPin
p Int
_) = Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ IPin -> Word8 -> Word8 -> Request
AnalogPinWrite IPin
p Word8
0 Word8
0
setNote :: Piezo -> Note -> Arduino ()
setNote :: Piezo -> Note -> Arduino ()
setNote (Piezo IPin
p Int
_) Note
n = Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ IPin -> Word8 -> Word8 -> Request
AnalogPinWrite IPin
p (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lsb) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
msb)
where f :: Int
f = Note -> Int
frequency Note
n
lsb :: Int
lsb = Int
f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7f
msb :: Int
msb = (Int
f Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7f
playNote :: Piezo -> (Note, Duration) -> Arduino ()
playNote :: Piezo -> (Note, Duration) -> Arduino ()
playNote Piezo
pz (Note
n, Duration
d) = do Piezo -> Note -> Arduino ()
setNote Piezo
pz Note
n
Int -> Arduino ()
delay (Piezo -> Duration -> Int
interval Piezo
pz Duration
d)
Piezo -> Arduino ()
silence Piezo
pz
playNotes :: Piezo -> [(Note, Duration)] -> Arduino ()
playNotes :: Piezo -> [(Note, Duration)] -> Arduino ()
playNotes Piezo
pz = [(Note, Duration)] -> Arduino ()
go
where go :: [(Note, Duration)] -> Arduino ()
go [] = Piezo -> Arduino ()
silence Piezo
pz
go (nd :: (Note, Duration)
nd@(Note
_, Duration
d):[(Note, Duration)]
r) = do Piezo -> (Note, Duration) -> Arduino ()
playNote Piezo
pz (Note, Duration)
nd
Int -> Arduino ()
delay (Piezo -> Duration -> Int
interval Piezo
pz Duration
d Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
3)
[(Note, Duration)] -> Arduino ()
go [(Note, Duration)]
r
rest :: Piezo -> Duration -> Arduino ()
rest :: Piezo -> Duration -> Arduino ()
rest Piezo
pz Duration
d = Int -> Arduino ()
delay (Piezo -> Duration -> Int
interval Piezo
pz Duration
d)