Difference between revisions of "User:Echo Nolan/Reactive Banana: Straight to the Point"

From HaskellWiki
Jump to navigation Jump to search
Line 5: Line 5:
 
All the tutorials on FRP ''I've'' read start with a long boring theory section. This is an instant gratification article. For starters, imagine a man attempting to sharpen a banana into a deadly weapon. See? You're gratified already! Now for a boring bit:
 
All the tutorials on FRP ''I've'' read start with a long boring theory section. This is an instant gratification article. For starters, imagine a man attempting to sharpen a banana into a deadly weapon. See? You're gratified already! Now for a boring bit:
   
Go install mplayer: <code-bash>apt-get install mplayer # Or equivalent for your OS/Distro</code-bash>
+
Go install sox: <code-bash>apt-get install sox # Or equivalent for your OS/Distro</code-bash>
   
 
Get the git repository associated with this tutorial: <code-bash>git clone https://github.com/enolan/rbsttp.git </code-bash>
 
Get the git repository associated with this tutorial: <code-bash>git clone https://github.com/enolan/rbsttp.git </code-bash>
   
Install reactive-banana <code-bash> cabal install reactive-banana</code-bash>
+
Install reactive-banana <code-bash>cabal install reactive-banana</code-bash>
   
 
== Musical interlude ==
 
== Musical interlude ==
Line 23: Line 23:
   
 
<pre-haskell>
 
<pre-haskell>
playNote C2
+
playNote (negate 5) C
playNote C6
+
playNote (negate 5) Fsharp
sequence_ . intersperse (threadDelay 1000000) $ map playNote [C2 ..]
+
sequence_ . intersperse (threadDelay 1000000) $ map (playNote (negate 5)) [C ..]
 
</pre-haskell>
 
</pre-haskell>
   
Line 31: Line 31:
   
 
<pre-haskell>
 
<pre-haskell>
sequence_ . intersperse (threadDelay 500000) $ map playNote [C2 ..]
+
sequence_ . intersperse (threadDelay 500000) $ map (playNote (negate 5)) [C ..]
sequence_ . intersperse (threadDelay 250000) $ map playNote [C2 ..]
+
sequence_ . intersperse (threadDelay 250000) $ map (playNote (negate 5)) [C ..]
sequence_ . intersperse (threadDelay 125000) $ map playNote [C2 ..]
+
sequence_ . intersperse (threadDelay 125000) $ map (playNote (negate 5)) [C ..]
sequence_ . intersperse (threadDelay 62500) $ map playNote [C2 ..]
+
sequence_ . intersperse (threadDelay 62500) $ map (playNote (negate 5)) [C ..]
 
</pre-haskell>
 
</pre-haskell>
   
You've probably figured out by now that C2 and C6 are data constructors. Here's the definition for my Note type.
+
You've probably figured out by now that C and Fsharp are data constructors. Here's the definition for my Note type.
   
 
<pre-haskell>
 
<pre-haskell>
  +
-- 12 note chromatic scale starting at middle C.
data Note = C2 | C3 | C4 | C5 | C6 deriving (Show, Enum)
 
  +
data Note =
  +
C | Csharp | D | Dsharp | E | F | Fsharp | G | Gsharp | A | Asharp | B
  +
| Cagain
 
deriving (Show, Enum)
 
</pre-haskell>
 
</pre-haskell>
   
<code-haskell>playNote</code-haskell> is the world's ugliest, hackiest synthesizer. Please don't look at its source. It's also asynchronous, which is why <code-haskell>mapM_ playNote [C2 ..]</code-haskell> doesn't sound very interesting.
+
<code-haskell>playNote</code-haskell> is a very hacky synthesizer. It's also asynchronous, which is why <code-haskell>mapM_ playNote [C ..]</code-haskell> doesn't sound too interesting. Here's <code-haskell>playNote</code-haskell>'s type.
  +
  +
<pre-haskell>
  +
-- Play a note with a given decibel gain relative to max volume, asynchronously.
  +
playNote :: Int -> Note -> IO ()
  +
</pre-haskell
   
 
== Ground yourself, then insert the electrodes into the banana ==
 
== Ground yourself, then insert the electrodes into the banana ==

Revision as of 22:57, 19 September 2012

Introduction

So I'm writing this tutorial as a means of teaching myself FRP and reactive-banana. It'll probably be full of errors and bad advice, use it at your own risk.

All the tutorials on FRP I've read start with a long boring theory section. This is an instant gratification article. For starters, imagine a man attempting to sharpen a banana into a deadly weapon. See? You're gratified already! Now for a boring bit:

Go install sox: <code-bash>apt-get install sox # Or equivalent for your OS/Distro</code-bash>

Get the git repository associated with this tutorial: <code-bash>git clone https://github.com/enolan/rbsttp.git </code-bash>

Install reactive-banana <code-bash>cabal install reactive-banana</code-bash>

Musical interlude

Cd into the git repo and open rbsttp.hs in GHCi:

<pre-bash> cd rbsttp ghci rbsttp.hs </pre-bash>

Now, we can make some beepy noises. Try these:

<pre-haskell> playNote (negate 5) C playNote (negate 5) Fsharp sequence_ . intersperse (threadDelay 1000000) $ map (playNote (negate 5)) [C ..] </pre-haskell>

Play with the value passed to threadDelay a bit for some more interesting noises. It's the time to wait between <code-haskell>Note</code-haskell>s, expresssed in microseconds.

<pre-haskell> sequence_ . intersperse (threadDelay 500000) $ map (playNote (negate 5)) [C ..] sequence_ . intersperse (threadDelay 250000) $ map (playNote (negate 5)) [C ..] sequence_ . intersperse (threadDelay 125000) $ map (playNote (negate 5)) [C ..] sequence_ . intersperse (threadDelay 62500) $ map (playNote (negate 5)) [C ..] </pre-haskell>

You've probably figured out by now that C and Fsharp are data constructors. Here's the definition for my Note type.

<pre-haskell> -- 12 note chromatic scale starting at middle C. data Note =

   C | Csharp | D | Dsharp | E | F | Fsharp | G | Gsharp | A | Asharp | B
   | Cagain
   deriving (Show, Enum)

</pre-haskell>

<code-haskell>playNote</code-haskell> is a very hacky synthesizer. It's also asynchronous, which is why <code-haskell>mapM_ playNote [C ..]</code-haskell> doesn't sound too interesting. Here's <code-haskell>playNote</code-haskell>'s type.

<pre-haskell> -- Play a note with a given decibel gain relative to max volume, asynchronously. playNote :: Int -> Note -> IO () </pre-haskell

Ground yourself, then insert the electrodes into the banana

"But Echo!", I hear you say "that's all in the IO monad!" You're right. We're going to free our synthesizer from the dark depths of imperative IO monad programming into the glorious light of declarative programming soon.