diff --git a/__init__.py b/__init__.py
index 63f7ca04081e597efcaef8bdb337dc0f5b44b5b9..baafce5a4d11aa7a1782010cfe98a30e5de4ea9b 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,226 +1,47 @@
-import sys
-import media, math, random
+import media, math
 from st3m.ui.colours import *
 from st3m.input import InputController
-from st3m.ui.view import BaseView, ViewManager, ViewTransitionSwipeLeft
-import leds
-
-sys.path.append('/flash/apps/PetalHero')
-
-import midi
-
-AMAZING_DIFFICULTY      = 0
-MEDIUM_DIFFICULTY       = 1
-EASY_DIFFICULTY         = 2
-SUPAEASY_DIFFICULTY     = 3
-
-noteMap = {     # difficulty, note
-  0x60: (AMAZING_DIFFICULTY,  0),
-  0x61: (AMAZING_DIFFICULTY,  1),
-  0x62: (AMAZING_DIFFICULTY,  2),
-  0x63: (AMAZING_DIFFICULTY,  3),
-  0x64: (AMAZING_DIFFICULTY,  4),
-  0x54: (MEDIUM_DIFFICULTY,   0),
-  0x55: (MEDIUM_DIFFICULTY,   1),
-  0x56: (MEDIUM_DIFFICULTY,   2),
-  0x57: (MEDIUM_DIFFICULTY,   3),
-  0x58: (MEDIUM_DIFFICULTY,   4),
-  0x48: (EASY_DIFFICULTY,     0),
-  0x49: (EASY_DIFFICULTY,     1),
-  0x4a: (EASY_DIFFICULTY,     2),
-  0x4b: (EASY_DIFFICULTY,     3),
-  0x4c: (EASY_DIFFICULTY,     4),
-  0x3c: (SUPAEASY_DIFFICULTY, 0),
-  0x3d: (SUPAEASY_DIFFICULTY, 1),
-  0x3e: (SUPAEASY_DIFFICULTY, 2),
-  0x3f: (SUPAEASY_DIFFICULTY, 3),
-  0x40: (SUPAEASY_DIFFICULTY, 4),
-}
-
-reverseNoteMap = dict([(v, k) for k, v in list(noteMap.items())])
-
-dim = lambda x, y: tuple(map(lambda x: x * y, x))
-
-class Event:
-  def __init__(self, length):
-    self.length = length
-
-class Note(Event):
-  def __init__(self, number, length, special = False, tappable = False):
-    Event.__init__(self, length)
-    self.number   = number
-    self.played   = False
-    self.special  = special
-    self.tappable = tappable
-    
-  def __repr__(self):
-    return "Note <#%d> length %d" % (self.number, self.length)
-
-class Tempo(Event):
-  def __init__(self, bpm):
-    super().__init__(0)
-    self.bpm = bpm
-    
-  def __repr__(self):
-    return "<%d bpm>" % self.bpm
-
-
-class MidiReader(midi.MidiOutStream.MidiOutStream):
-  def __init__(self, song):
-    super().__init__()
-    self.song = song
-    self.bpm = 0
-    self.heldNotes = {}
-    self.velocity  = {}
-    self.ticksPerBeat = 480
-    self.tempoMarkers = []
-
-  def addEvent(self, track, event, time = None):
-    if time is None:
-      time = self.abs_time()
-    assert time >= 0
-    #print('addEvent', track, event, time)
-    #if track is None:
-    #  for t in self.song.tracks:
-    #    t.addEvent(time, event)
-    #elif track < len(self.song.tracks):
-    #  self.song.tracks[track].addEvent(time, event)
-
-  def abs_time(self):
-    def ticksToBeats(ticks, bpm):
-      return (60000.0 * ticks) / (bpm * self.ticksPerBeat)
-
-    if self.bpm:
-      currentTime = midi.MidiOutStream.MidiOutStream.abs_time(self)
-
-      # Find out the current scaled time.
-      # Yeah, this is reeally slow, but fast enough :)
-      scaledTime      = 0.0
-      tempoMarkerTime = 0.0
-      currentBpm      = self.bpm
-      for i, marker in enumerate(self.tempoMarkers):
-        time, bpm = marker
-        if time > currentTime:
-          break
-        scaledTime += ticksToBeats(time - tempoMarkerTime, currentBpm)
-        tempoMarkerTime, currentBpm = time, bpm
-      return scaledTime + ticksToBeats(currentTime - tempoMarkerTime, currentBpm)
-    return 0.0
-
-  def header(self, format, nTracks, division):
-    self.ticksPerBeat = division
-    
-  def tempo(self, value):
-    bpm = 60.0 * 10.0**6 / value
-    self.tempoMarkers.append((midi.MidiOutStream.MidiOutStream.abs_time(self), bpm))
-    if not self.bpm:
-      self.bpm = bpm
-      #self.song.setBpm(bpm)
-    #print('bpm', bpm)
-    self.addEvent(None, Tempo(bpm))
-
-  def note_on(self, channel, note, velocity):
-    if self.get_current_track() > 1: return
-    self.velocity[note] = velocity
-    self.heldNotes[(self.get_current_track(), channel, note)] = self.abs_time()
-
-  def note_off(self, channel, note, velocity):
-    if self.get_current_track() > 1: return
-    try:
-      startTime = self.heldNotes[(self.get_current_track(), channel, note)]
-      endTime   = self.abs_time()
-      del self.heldNotes[(self.get_current_track(), channel, note)]
-      if note in noteMap:
-        track, number = noteMap[note]
-        self.addEvent(track, Note(number, endTime - startTime, special = self.velocity[note] == 127), time = startTime)
-      else:
-        print("MIDI note 0x%x at %d does not map to any game note." % (note, self.abs_time()))
-        pass
-    except KeyError:
-      print("MIDI note 0x%x on channel %d ending at %d was never started." % (note, channel, self.abs_time()))
-
-
+from st3m.ui.view import ViewTransitionSwipeLeft
 from st3m.application import Application, ApplicationContext
 import st3m.run
 import leds
+import time
+import bl00mbox
 
+# TODO: FIXME
+import sys
+sys.path.append('/flash/apps/PetalHero')
 
-class Flower:
-    def __init__(self, x: float, y: float, z: float) -> None:
-        self.x = x
-        self.y = y
-        self.z = z
-        self.rot = 0.0
-        self.rot_speed = 1 / 800 #(((random.getrandbits(16) - 32767) / 32767.0) - 0.5) / 800
-
-    def draw(self, ctx: Context) -> None:
-        ctx.save()
-        ctx.rotate(self.rot)
-        ctx.translate(-78 + self.x, -70 + self.y)
-        #ctx.translate(50, 40)
-
-        #ctx.translate(-50, -40)
-        #ctx.scale(100 / self.z, 100.0 / self.z)
-        ctx.move_to(76.221727, 3.9788409).curve_to(
-            94.027758, 31.627675, 91.038918, 37.561293, 94.653428, 48.340473
-        ).rel_curve_to(
-            25.783102, -3.90214, 30.783332, -1.52811, 47.230192, 4.252451
-        ).rel_curve_to(
-            -11.30184, 19.609496, -21.35729, 20.701768, -35.31018, 32.087063
-        ).rel_curve_to(
-            5.56219, 12.080061, 12.91196, 25.953973, 9.98735, 45.917643
-        ).rel_curve_to(
-            -19.768963, -4.59388, -22.879866, -10.12216, -40.896842, -23.93099
-        ).rel_curve_to(
-            -11.463256, 10.23025, -17.377386, 18.2378, -41.515124, 25.03533
-        ).rel_curve_to(
-            0.05756, -29.49286, 4.71903, -31.931936, 10.342734, -46.700913
-        ).curve_to(
-            33.174997, 77.048676, 19.482194, 71.413009, 8.8631648, 52.420793
-        ).curve_to(
-            27.471602, 45.126773, 38.877997, 45.9184, 56.349456, 48.518302
-        ).curve_to(
-            59.03275, 31.351935, 64.893201, 16.103886, 76.221727, 3.9788409
-        ).close_path().fill()
-        ctx.restore()
-
-class SecondScreen(BaseView):
-    def draw(self, ctx: Context) -> None:
-        # Paint the background black
-        ctx.rgb(0, 0, 0).rectangle(-120, -120, 240, 240).fill()
-        # Green square
-        ctx.rgb(0, 255, 0).rectangle(-20, -20, 40, 40).fill()
-
-    def think(self, ins: InputState, delta_ms: int) -> None:
-        self.input.think(ins, delta_ms)
-        media.think(delta_ms)
+import song
+import flower
+import utils
 
-    def on_enter(self, vm: Optional[ViewManager]) -> None:
-        super().on_enter(vm)
-        #self._vm = vm
-        # Ignore the button which brought us here until it is released
-        #self.input._ignore_pressed()
-        media.load('/sd/song.mp3')
-
-class App(Application):
+class PetalHero(Application):
     def __init__(self, app_ctx: ApplicationContext) -> None:
         super().__init__(app_ctx)
         self.input = InputController()
         self.path = getattr(app_ctx, 'bundle_path', '/flash/apps/PetalHero')
         if not self.path:
             self.path = '/flash/apps/PetalHero'
-        print(self.path)
-        midiIn = midi.MidiInFile(MidiReader(None), self.path + '/notes.mid')
-        #midiIn.read()
 
-        self.flower = Flower(0, 0, 0.01)
+        self.flower = flower.Flower(0, 0, 0.01)
         self.time = 0
         self.repeats = 0
 
-    def draw(self, ctx: Context):
-        ctx.rgb(*GO_GREEN)
-        ctx.rgb(*PUSH_RED)
+        self.blm = bl00mbox.Channel("Petal Hero")
+
+        self.in_sound = self.blm.new(bl00mbox.patches.sampler, self.path + "/in.wav")
+        self.in_sound.signals.output = self.blm.mixer
+
+        self.out_sound = self.blm.new(bl00mbox.patches.sampler, self.path + "/out.wav")
+        self.out_sound.signals.output = self.blm.mixer
 
+        self.crunch_sound = []
+        for i in range(3):
+            self.crunch_sound.append(self.blm.new(bl00mbox.patches.sampler, self.path + "/crunch" + str(i+1) + ".wav"))
+            self.crunch_sound[i].signals.output = self.blm.mixer
+
+    def draw(self, ctx: Context):
         ctx.linear_gradient(-120, -120, 120, 120)
 
         ctx.add_stop(0.0, [94, 0, 0], 1.0)
@@ -263,6 +84,7 @@ class App(Application):
     def think(self, ins: InputState, delta_ms: int) -> None:
         self.input.think(ins, delta_ms)
         media.think(delta_ms)
+
         for c in [self.flower]:
             c.rot += float(delta_ms) * c.rot_speed
         self.time += delta_ms / 1000
@@ -272,7 +94,11 @@ class App(Application):
             self.repeats += 1
 
         if self.input.buttons.app.middle.pressed:
-            self.vm.push(SecondScreen(), ViewTransitionSwipeLeft())
+            self.in_sound.signals.trigger.start()
+            self.vm.push(song.SongView(self), ViewTransitionSwipeLeft())
+
+        if self.input.buttons.os.middle.pressed:
+            self.out_sound.signals.trigger.start()
 
         if self.exiting:
             return
@@ -282,14 +108,14 @@ class App(Application):
         led = -3
         for col in [RED, (1.0, 1.0, 0.0), BLUE, PUSH_RED, GO_GREEN]:
             for i in range(7):
-                leds.set_rgb(led if led >= 0 else led + 40, *dim(col, -math.cos(self.time) / 2 + 0.5))
+                leds.set_rgb(led if led >= 0 else led + 40, *utils.dim(col, -math.cos(self.time) / 2 + 0.5))
                 led += 1
             leds.set_rgb(led, 0, 0, 0)
             led += 1
             
         leds.update()
 
-    def on_enter(self, vm: Optional[ViewManager]) -> None:
+    def on_enter(self, vm) -> None:
         super().on_enter(vm)
         #self._vm = vm
         # Ignore the button which brought us here until it is released
@@ -308,6 +134,5 @@ class App(Application):
         leds.set_brightness(69)
         leds.update()
 
-
 if __name__ == '__main__':
-    st3m.run.run_view(App(ApplicationContext()))
+    st3m.run.run_app(PetalHero)
diff --git a/crunch1.wav b/crunch1.wav
new file mode 100644
index 0000000000000000000000000000000000000000..345b996cd5f711cc6b10bdac550f61ba938b07b8
Binary files /dev/null and b/crunch1.wav differ
diff --git a/crunch2.wav b/crunch2.wav
new file mode 100644
index 0000000000000000000000000000000000000000..3b1ae8564006dffcf6c659206080ea0d82cc1255
Binary files /dev/null and b/crunch2.wav differ
diff --git a/crunch3.wav b/crunch3.wav
new file mode 100644
index 0000000000000000000000000000000000000000..cc801005d913221b6c9a385953322d621c459a16
Binary files /dev/null and b/crunch3.wav differ
diff --git a/flow3r.toml b/flow3r.toml
index c8d926ce541de5999acf8d8781fae39951a99172..f3aba575ef3131ad59b5df87fee0955e0f37cefc 100644
--- a/flow3r.toml
+++ b/flow3r.toml
@@ -3,7 +3,7 @@ name = "Petal Hero"
 menu = "Music"
 
 [entry]
-class = "App"
+class = "PetalHero"
 
 [metadata]
 author = "dos"
diff --git a/flower.py b/flower.py
new file mode 100644
index 0000000000000000000000000000000000000000..29bf1615ef5820a820d5db7db888fc45794a3210
--- /dev/null
+++ b/flower.py
@@ -0,0 +1,38 @@
+class Flower:
+    def __init__(self, x: float, y: float, z: float) -> None:
+        self.x = x
+        self.y = y
+        self.z = z
+        self.rot = 0.0
+        self.rot_speed = 1 / 800 #(((random.getrandbits(16) - 32767) / 32767.0) - 0.5) / 800
+
+    def draw(self, ctx: Context) -> None:
+        ctx.save()
+        ctx.rotate(self.rot)
+        ctx.translate(-78 + self.x, -70 + self.y)
+        #ctx.translate(50, 40)
+
+        #ctx.translate(-50, -40)
+        #ctx.scale(100 / self.z, 100.0 / self.z)
+        ctx.move_to(76.221727, 3.9788409).curve_to(
+            94.027758, 31.627675, 91.038918, 37.561293, 94.653428, 48.340473
+        ).rel_curve_to(
+            25.783102, -3.90214, 30.783332, -1.52811, 47.230192, 4.252451
+        ).rel_curve_to(
+            -11.30184, 19.609496, -21.35729, 20.701768, -35.31018, 32.087063
+        ).rel_curve_to(
+            5.56219, 12.080061, 12.91196, 25.953973, 9.98735, 45.917643
+        ).rel_curve_to(
+            -19.768963, -4.59388, -22.879866, -10.12216, -40.896842, -23.93099
+        ).rel_curve_to(
+            -11.463256, 10.23025, -17.377386, 18.2378, -41.515124, 25.03533
+        ).rel_curve_to(
+            0.05756, -29.49286, 4.71903, -31.931936, 10.342734, -46.700913
+        ).curve_to(
+            33.174997, 77.048676, 19.482194, 71.413009, 8.8631648, 52.420793
+        ).curve_to(
+            27.471602, 45.126773, 38.877997, 45.9184, 56.349456, 48.518302
+        ).curve_to(
+            59.03275, 31.351935, 64.893201, 16.103886, 76.221727, 3.9788409
+        ).close_path().fill()
+        ctx.restore()
diff --git a/in.wav b/in.wav
new file mode 100644
index 0000000000000000000000000000000000000000..43307dda201211c4217a42f9a8a51e9e329cdcb0
Binary files /dev/null and b/in.wav differ
diff --git a/midireader.py b/midireader.py
new file mode 100644
index 0000000000000000000000000000000000000000..8494132352e3b0820a1ef364683873cd851958bb
--- /dev/null
+++ b/midireader.py
@@ -0,0 +1,117 @@
+import midi
+
+AMAZING_DIFFICULTY      = 0
+MEDIUM_DIFFICULTY       = 1
+EASY_DIFFICULTY         = 2
+SUPAEASY_DIFFICULTY     = 3
+
+baseNotes = {
+  0x60: AMAZING_DIFFICULTY,
+  0x54: MEDIUM_DIFFICULTY,
+  0x48: EASY_DIFFICULTY,
+  0x3c: SUPAEASY_DIFFICULTY
+}
+
+noteMap = {}
+for basenote, diff in baseNotes.items():
+  for note in range(5):
+    noteMap[basenote + note] = (diff, note)
+
+reverseNoteMap = dict([(v, k) for k, v in list(noteMap.items())])
+
+class Event:
+  def __init__(self, length):
+    self.length = length
+
+class Note(Event):
+  def __init__(self, number, length, special = False, tappable = False):
+    super().__init__(length)
+    self.number   = number
+    self.played   = False
+    self.special  = special
+    self.tappable = tappable
+    
+  def __repr__(self):
+    return "<Note #%d length: %d>" % (self.number, self.length)
+
+class Tempo(Event):
+  def __init__(self, bpm):
+    super().__init__(0)
+    self.bpm = bpm
+
+  def __repr__(self):
+    return "<%d bpm>" % self.bpm
+
+class MidiReader(midi.MidiOutStream.MidiOutStream):
+  def __init__(self, song):
+    super().__init__()
+    self.song = song
+    self.bpm = 0
+    self.heldNotes = {}
+    self.velocity  = {}
+    self.ticksPerBeat = 480
+    self.tempoMarkers = []
+
+  def addEvent(self, track, event, time = None):
+    if time is None:
+      time = self.abs_time()
+    assert time >= 0
+    #print('addEvent', track, event, time)
+    #if track is None:
+    #  for t in self.song.tracks:
+    #    t.addEvent(time, event)
+    #elif track < len(self.song.tracks):
+    #  self.song.tracks[track].addEvent(time, event)
+
+  def abs_time(self):
+    def ticksToBeats(ticks, bpm):
+      return (60000.0 * ticks) / (bpm * self.ticksPerBeat)
+
+    if self.bpm:
+      currentTime = midi.MidiOutStream.MidiOutStream.abs_time(self)
+
+      # Find out the current scaled time.
+      # Yeah, this is reeally slow, but fast enough :)
+      scaledTime      = 0.0
+      tempoMarkerTime = 0.0
+      currentBpm      = self.bpm
+      for i, marker in enumerate(self.tempoMarkers):
+        time, bpm = marker
+        if time > currentTime:
+          break
+        scaledTime += ticksToBeats(time - tempoMarkerTime, currentBpm)
+        tempoMarkerTime, currentBpm = time, bpm
+      return scaledTime + ticksToBeats(currentTime - tempoMarkerTime, currentBpm)
+    return 0.0
+
+  def header(self, format, nTracks, division):
+    self.ticksPerBeat = division
+    
+  def tempo(self, value):
+    bpm = 60.0 * 10.0**6 / value
+    self.tempoMarkers.append((midi.MidiOutStream.MidiOutStream.abs_time(self), bpm))
+    if not self.bpm:
+      self.bpm = bpm
+      #self.song.setBpm(bpm)
+    #print('bpm', bpm)
+    self.addEvent(None, Tempo(bpm))
+
+  def note_on(self, channel, note, velocity):
+    if self.get_current_track() > 1: return
+    self.velocity[note] = velocity
+    self.heldNotes[(self.get_current_track(), channel, note)] = self.abs_time()
+
+  def note_off(self, channel, note, velocity):
+    if self.get_current_track() > 1: return
+    try:
+      startTime = self.heldNotes[(self.get_current_track(), channel, note)]
+      endTime   = self.abs_time()
+      del self.heldNotes[(self.get_current_track(), channel, note)]
+      if note in noteMap:
+        track, number = noteMap[note]
+        self.addEvent(track, Note(number, endTime - startTime, special = self.velocity[note] == 127), time = startTime)
+      else:
+        print("MIDI note 0x%x at %d does not map to any game note." % (note, self.abs_time()))
+        pass
+    except KeyError:
+      print("MIDI note 0x%x on channel %d ending at %d was never started." % (note, channel, self.abs_time()))
diff --git a/out.wav b/out.wav
new file mode 100644
index 0000000000000000000000000000000000000000..03396dcd839a5165d4be59c67018e648fea85fd5
Binary files /dev/null and b/out.wav differ
diff --git a/song.py b/song.py
new file mode 100644
index 0000000000000000000000000000000000000000..f799c0ff020a69ecd8fd30173e499e0054fcf020
--- /dev/null
+++ b/song.py
@@ -0,0 +1,35 @@
+from st3m.input import InputController
+from st3m.ui.view import BaseView, ViewManager, ViewTransitionSwipeLeft
+from st3m.application import Application, ApplicationContext
+import media
+
+import midi
+import midireader
+
+class SongView(BaseView):
+    def __init__(self, app):
+        super().__init__()
+        self.app = app
+        midiIn = midi.MidiInFile(midireader.MidiReader(None), self.app.path + '/notes.mid')
+        midiIn.read()
+
+    def draw(self, ctx: Context) -> None:
+        # Paint the background black
+        ctx.rgb(0, 0, 0).rectangle(-120, -120, 240, 240).fill()
+        # Green square
+        ctx.rgb(0, 255, 0).rectangle(-20, -20, 40, 40).fill()
+
+    def think(self, ins: InputState, delta_ms: int) -> None:
+        self.input.think(ins, delta_ms)
+        media.think(delta_ms)
+
+    def on_enter(self, vm: Optional[ViewManager]) -> None:
+        super().on_enter(vm)
+        #self._vm = vm
+        # Ignore the button which brought us here until it is released
+        #self.input._ignore_pressed()
+        media.load('/sd/song.mp3')
+
+    def on_exit(self):
+        super().on_exit()
+        self.app.out_sound.signals.trigger.start()
diff --git a/start.mp3 b/start.mp3
new file mode 100644
index 0000000000000000000000000000000000000000..8968a6911ccdd522fbfdfc48c73ece8362a924bf
Binary files /dev/null and b/start.mp3 differ
diff --git a/utils.py b/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..54289b98b81d52b967a9ccccd3db187e19529156
--- /dev/null
+++ b/utils.py
@@ -0,0 +1 @@
+dim = lambda x, y: tuple(map(lambda x: x * y, x))