diff --git a/__init__.py b/__init__.py
index 1850f04961279d9feb2ac7b56e3bc79e1ed9bdc8..62b5e275894e676449b4361c4a87859f7ecd38fc 100644
--- a/__init__.py
+++ b/__init__.py
@@ -6,6 +6,7 @@ import st3m.run
 import leds
 import bl00mbox
 from time import sleep
+import sys_display
 UNSUPPORTED = False
 try:
     import media
@@ -36,9 +37,13 @@ class PetalHero(Application):
         self.after_score = False
         #self.blm_extra = bl00mbox.Channel("Petal Hero Extra")
         #self.blm_extra.background_mute_override = True
+        
+        self.blm_timeout = 1
 
         readme.install()
 
+    #def show_icons(self): return True
+
     def load(self):
         if self.loaded:
             return
@@ -60,8 +65,13 @@ class PetalHero(Application):
         self.loaded = True
 
     def load_fiba(self):
+        if not self.loaded:
+            return
+
         if self.app.fiba_sound:
             return
+        
+        utils.blm_wake(self, 1)
 
         self.app.fiba_sound = []
         for i in range(6):
@@ -135,6 +145,7 @@ class PetalHero(Application):
 
         media.think(delta_ms)
         self.flower.think(delta_ms)
+        utils.blm_timeout(self, delta_ms)
 
         if self.time < 0:
             self.time = 0
@@ -167,15 +178,16 @@ class PetalHero(Application):
             self.load()
         media.load(self.path + '/sounds/menu.mp3')
         self.time = -1
-        leds.set_brightness(69)
+        leds.set_slew_rate(255)
+        leds.set_auto_update(0)
 
     def on_exit(self):
         super().on_exit()
         if UNSUPPORTED:
             return
         media.stop()
+        leds.set_slew_rate(255)
         leds.set_all_rgb(0, 0, 0)
-        leds.set_brightness(69)
         leds.update()
         if self.vm.direction == ViewTransitionDirection.BACKWARD:
             utils.play_back(self.app)
diff --git a/difficulty.py b/difficulty.py
index 1b420fdf9e25f6277a9888fd586d96694748ec85..05e26ef20f2740fee21436183f52db4c61bb81a1 100644
--- a/difficulty.py
+++ b/difficulty.py
@@ -104,16 +104,17 @@ class DifficultyView(BaseView):
         self._sc.think(ins, delta_ms)
         media.think(delta_ms)
         self.flower.think(delta_ms)
+        utils.blm_timeout(self, delta_ms)
         self._scroll_pos += delta_ms / 1000
 
         if not self.is_active():
             return
 
-        if self.input.buttons.app.left.pressed:
+        if self.input.buttons.app.left.pressed or self.input.buttons.app.left.repeated:
             self._sc.scroll_left()
             self._scroll_pos = 0.0
             utils.play_crunch(self.app)
-        elif self.input.buttons.app.right.pressed:
+        elif self.input.buttons.app.right.pressed or self.input.buttons.app.right.repeated:
             self._sc.scroll_right()
             self._scroll_pos = 0.0
             utils.play_crunch(self.app)
diff --git a/loading.py b/loading.py
index 043d105c0772633c75f2ad9e81df27b0713b2b35..05f0bfb0dac413e62fec6898c7f79c534befebbd 100644
--- a/loading.py
+++ b/loading.py
@@ -3,6 +3,7 @@ import gc
 import sys_display
 
 import song
+import utils
 
 class LoadingView(BaseView):
     def __init__(self, app, song, difficulty):
@@ -23,6 +24,7 @@ class LoadingView(BaseView):
         ctx.text("Loading...")
 
     def think(self, ins: InputState, delta_ms: int) -> None:
+        utils.blm_timeout(self, delta_ms)
         if self.vm.transitioning or not self.is_active(): return
         #gc.collect()
         self.vm.replace(song.SongView(self.app, self.song, self.difficulty), ViewTransitionBlend())
diff --git a/midi/EventDispatcher.py b/midi/EventDispatcher.py
index 85982aaf9966dca6b52ccc114ae3ff26b5b287c9..1a617550f56b663323aa5f1d01ef7fdac331ac77 100644
--- a/midi/EventDispatcher.py
+++ b/midi/EventDispatcher.py
@@ -192,7 +192,6 @@ class EventDispatcher:
             # uses 3 bytes to represent time between quarter 
             # notes in microseconds
             stream.tempo((b1<<16) + (b2<<8) + b3)
-        return        
         
         # SEQUENCE_NUMBER = 0x00 (00 02 ss ss (seq-number))
         if meta_type == SEQUENCE_NUMBER:
diff --git a/midi/MidiFileParser.py b/midi/MidiFileParser.py
index d0b6bd0290d587fb25d8dc7a86b9a1c1c2020f9b..fed6e375b6b89ccd002d6bb4735df57cdf9a754b 100644
--- a/midi/MidiFileParser.py
+++ b/midi/MidiFileParser.py
@@ -77,6 +77,7 @@ class MidiFileParser:
         "Parses a track chunk. This is the most important part of the parser."
         
         # set time to 0 at start of a track
+        self.ignored = False
         self.dispatch.reset_time()
         
         dispatch = self.dispatch
@@ -126,20 +127,25 @@ class MidiFileParser:
                 meta_type = raw_in.readBew()
                 meta_length = raw_in.readVarLen()
                 meta_data = raw_in.nextSlice(meta_length)
+                if self.ignored and meta_type != TEMPO: return
                 if not meta_length: return
-                dispatch.meta_event(meta_type, meta_data)
-                if meta_type == END_OF_TRACK: return
+                res = dispatch.meta_event(meta_type, meta_data)
+                if meta_type == SEQUENCE_NAME:
+                    self.ignored = res
+                if meta_type == END_OF_TRACK:
+                    return
             # Oh! Then it must be a midi event (channel voice message)
             else:
                 data_size = data_sizes.get(hi_nible, 0)
                 channel_data = raw_in.nextSlice(data_size)
+                if self.ignored: return
                 event_type, channel = hi_nible, lo_nible
                 dispatch.channel_messages(event_type, channel, channel_data)
 
 
     def parseMTrkChunks(self):
         "Parses all track chunks."
-        for t in range(min(2, self.nTracks)):
+        for t in range(self.nTracks):
             self._current_track = t
             self.parseMTrkChunk() # this is where it's at!
         self.dispatch.eof()
diff --git a/midireader.py b/midireader.py
index dc631e8a1b4df70085212f424b19711d7b50bc89..b02c67264e80fbee6eedeef2392d8cf60e075c10 100644
--- a/midireader.py
+++ b/midireader.py
@@ -17,10 +17,10 @@ class Difficulty:
     return self.text
 
 difficulties = {
-  SUPAEASY_DIFFICULTY: Difficulty(SUPAEASY_DIFFICULTY, "Supaeasy"),
-  EASY_DIFFICULTY:     Difficulty(EASY_DIFFICULTY,     "Easy"),
-  MEDIUM_DIFFICULTY:   Difficulty(MEDIUM_DIFFICULTY,   "Medium"),
-  AMAZING_DIFFICULTY:  Difficulty(AMAZING_DIFFICULTY,  "Amazing"),
+  SUPAEASY_DIFFICULTY: Difficulty(SUPAEASY_DIFFICULTY, "Easy"),
+  EASY_DIFFICULTY:     Difficulty(EASY_DIFFICULTY,     "Medium"),
+  MEDIUM_DIFFICULTY:   Difficulty(MEDIUM_DIFFICULTY,   "Hard"),
+  AMAZING_DIFFICULTY:  Difficulty(AMAZING_DIFFICULTY,  "Expert"),
 }
 
 baseNotes = {
@@ -37,6 +37,8 @@ for basenote, diff in baseNotes.items():
 
 reverseNoteMap = dict([(v, k) for k, v in list(noteMap.items())])
 
+noteSet = set(noteMap.keys())
+
 class Event:
   __slots__ = ("length", "time")
 
@@ -119,6 +121,8 @@ class MidiReader(midi.MidiOutStream):
     #self.tracks        = [Track() for t in range(len(difficulties))]
     self.difficulty = difficulty
     self.track = Track()
+    self.nTracks = -1
+    self.ignored = False
 
   def addEvent(self, track, event):
     time = event.time
@@ -158,8 +162,10 @@ class MidiReader(midi.MidiOutStream):
 
   def header(self, format, nTracks, division):
     self.ticksPerBeat = division
+    self.nTracks = nTracks
     
   def tempo(self, value):
+    #if self.ignored: return
     bpm = 60.0 * 10.0**6 / value
     if not self.tempoMarkers or bpm != self.tempoMarkers[-1][1]:
         self.tempoMarkers.append((midi.MidiOutStream.abs_time(self), bpm))
@@ -170,24 +176,30 @@ class MidiReader(midi.MidiOutStream):
     #print('bpm', bpm)
     #self.addEvent(None, Tempo(bpm))
 
+  def sequence_name(self, val):
+    name = ''.join(list(map(chr, val)))
+    #print(name)
+    self.ignored = name != "PART GUITAR" and self.nTracks > 2
+    return self.ignored
+
   def note_on(self, channel, note, velocity):
-    if self.get_current_track() > 1: return
+    if self.ignored: return
     #print("note_on", channel, note, velocity, self.abs_time())
+    if not note in noteMap:
+      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
+    if self.ignored: return
     #print("note_off", channel, note, velocity, self.abs_time())
+    if not note in noteMap:
+      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(startTime, number, endTime - startTime, special = self.velocity[note] == 127))
-      else:
-        #print("MIDI note 0x%x at %d does not map to any game note." % (note, self.abs_time()))
-        pass
+      track, number = noteMap[note]
+      self.addEvent(track, Note(startTime, number, endTime - startTime, special = self.velocity[note] == 127))
     except KeyError:
       print("MIDI note 0x%x on channel %d ending at %d was never started." % (note, channel, self.abs_time()))
diff --git a/readme.py b/readme.py
index 09e5e461f7d6f056366c80ee80a80d3819fddbad..1de3855ba4b5af60700aaae836ff10db4e29e7e6 100644
--- a/readme.py
+++ b/readme.py
@@ -7,7 +7,7 @@ Petal Hero is compatible with songs for Frets on Fire, but with
 one caveat: you need to mix audio tracks and save them as MP3.
 This should do:
 
-  sox -m *.ogg -c 1 -C 64 -r 48000 song.mp3
+  sox -m *.ogg -c 1 -C 128 -r 48k song.mp3 norm -3
 
 You need song.ini, song.mp3 and notes.mid in the song directory.
 """
diff --git a/score.py b/score.py
index 3098f23cc663bfe6942925adba9de2be7a44d245..20a48ff232879583ff3e271c73126a3ab39c057d 100644
--- a/score.py
+++ b/score.py
@@ -92,6 +92,7 @@ class ScoreView(BaseView):
     def think(self, ins: InputState, delta_ms: int) -> None:
         super().think(ins, delta_ms)
         media.think(delta_ms)
+        utils.blm_timeout(self, delta_ms)
         self.time += delta_ms / 1000
         
         if self.time > 1.5 and not self.played:
diff --git a/select.py b/select.py
index a9080ff8b96746c2a4f7aac698c0f88d21b4c39c..9a5317cb28fb1bcd157dbd80f869fba0fdbbb9fd 100644
--- a/select.py
+++ b/select.py
@@ -182,6 +182,7 @@ class SelectView(BaseView):
     def think(self, ins: InputState, delta_ms: int) -> None:
         super().think(ins, delta_ms)
         self._sc.think(ins, delta_ms)
+        utils.blm_timeout(self, delta_ms)
         if not self.to_process and not self.processing_now:
             media.think(delta_ms)
         self.flower.think(delta_ms)
@@ -191,11 +192,14 @@ class SelectView(BaseView):
         if cur_target < 0: cur_target = 0
         if cur_target > len(self.songs) - 1: cur_target = len(self.songs) - 1
 
-        if self.input.buttons.app.left.pressed:
+        if not self.is_active():
+            return
+
+        if self.input.buttons.app.left.pressed or self.input.buttons.app.left.repeated:
             self._sc.scroll_left()
             self._scroll_pos = 0.0
             utils.play_crunch(self.app)
-        elif self.input.buttons.app.right.pressed:
+        elif self.input.buttons.app.right.pressed or self.input.buttons.app.right.repeated:
             self._sc.scroll_right()
             self._scroll_pos = 0.0
             utils.play_crunch(self.app)
@@ -204,9 +208,6 @@ class SelectView(BaseView):
         if pos < 0: pos = 0
         if pos > len(self.songs) - 1: pos = len(self.songs) - 1
 
-        if not self.is_active():
-            return
-
         if pos != cur_target:
             media.load(self.songs[pos].dirName + "/song.mp3")
 
diff --git a/song.py b/song.py
index 16ddd123f1e02986974cbf78de055e46c30a1e73..3bbea0d28387cc2a60d8017cde6a29199c67b9fb 100644
--- a/song.py
+++ b/song.py
@@ -5,7 +5,9 @@ import st3m.run
 import math
 import leds
 import sys_display
+import sys_scope
 from micropython import const
+from time import ticks_ms
 try:
     import media
     from st3m.ui.view import ViewTransitionDirection
@@ -63,16 +65,20 @@ class SongView(BaseView):
         self.notes = set()
         self.events_in_margin = set()
         self.petal_events = [set() for i in range(5)]
+        self.last_played = 0
         
         self.good = 0.0
         self.bad = 0.0
         self.missed = [0.0] * 5
         self.miss = 0.0
 
-        self.oldmem = 0
+        #self.oldmem = 0
+        #self.redraw = True
+        #self.acc = 0
 
     def draw(self, ctx: Context) -> None:
         #mem = gc.mem_alloc()
+        #self.redraw = True
         self.time += VIDEO_DELAY
         
         other = int(self.time / 2 / self.data.period) % 2
@@ -211,16 +217,26 @@ class SongView(BaseView):
         
         ctx.save()
         ctx.rgb(0.5 + self.bad * 0.4, 0.5, 0.5)
+        #ctx.rectangle(-8, -8, 15, 15)
+        #ctx.clip()
+        ctx.line_width = 12
+        ctx.scale(0.0625, 0.125 * 0.3)
         #ctx.rotate(wiggle)
+        ctx.begin_path()
         if self.started:
-            ctx.rectangle(-8, -8, 15, 15)
-            ctx.clip() # for firmwares that stroke the scope...
-            ctx.scale(0.0625, 0.125 * 0.3)
-            ctx.begin_path()
-            ctx.scope()
-            ctx.line_to(120, 0)
-            ctx.line_to(-120, 0)
+            buf = sys_scope.get_buffer_x()
+            ctx.move_to(-120, 0)
+            for i in range(0, len(buf), 32):
+                val = buf[i] / 32
+                ctx.line_to(-120 + i, max(6, val))
+            for i in range(len(buf) - 1, 0, -32):
+                val = buf[i] / 32
+                ctx.line_to(-120 + i, min(-6, val))
             ctx.fill()
+        else:
+            ctx.move_to(-120, 0)
+            ctx.line_to(120, 0)
+            ctx.stroke()
         ctx.restore()
         
         ctx.gray(0.8)
@@ -248,13 +264,25 @@ class SongView(BaseView):
             ctx.font_size = 64
             ctx.text("PAUSED")
         #print("draw", gc.mem_alloc() - mem)
+        #t = ticks_ms()
+        #print(ticks_ms() - t)
 
     def think(self, ins: InputState, delta_ms: int) -> None:
         #mem = gc.mem_alloc()
         #print(mem - self.oldmem)
         #self.oldmem = mem
+
+        #self.acc += delta_ms
+        #if self.redraw:
+        #    delta_ms = self.acc
+        #    self.acc = 0
+        #    self.redraw = False
+        #else:
+        #    return
+        #if (delta_ms > 100): print(delta_ms)
         
         super().think(ins, delta_ms)
+        utils.blm_timeout(self, delta_ms)
 
         if self.first_think:
             self.first_think = False
@@ -262,7 +290,7 @@ class SongView(BaseView):
 
         media.think(delta_ms)
 
-        if self.input.buttons.os.middle.pressed and not self.is_active():
+        if self.input.buttons.os.middle.pressed and not self.is_active(): # TODO: will that work with pending transitions?
             self.vm.push(self)
             self.vm.pop(ViewTransitionSwipeRight(), depth=2)
             return
@@ -273,6 +301,7 @@ class SongView(BaseView):
         if self.song and self.started and media.get_position() == media.get_duration() and not self.finished:
             self.finished = True
             media.stop()
+            gc.collect()
             self.vm.replace(score.ScoreView(self.app, self.data, self.longeststreak), ViewTransitionBlend())
             return
 
@@ -316,7 +345,7 @@ class SongView(BaseView):
             self.petal_events[i].clear()
 
         earlyMargin       = 60000.0 / self.data.bpm / 3.5
-        lateMargin        = 60000.0 / self.data.bpm / 3.5
+        lateMargin        = 60000.0 / self.data.bpm / 3.5 + delta_ms
 
         self.notes.clear()
         self.events_in_margin.clear()
@@ -340,6 +369,8 @@ class SongView(BaseView):
                     if not self.demo_mode:
                         self.missed[event.number] = 1.0
                         self.miss = 1.0
+                        if event.time >= self.last_played:
+                            media.set_volume(0.25)
                 if event.played and event.time + event.length - lateMargin > self.time:
                     p = 4 if event.number == 0 else event.number - 1
                     if not ins.captouch.petals[p*2].pressed and not event.missed:
@@ -366,7 +397,7 @@ class SongView(BaseView):
                             event = e
                     #event = sorted(events, key = lambda x: x.time)[0]
                     event.played = True
-                    self.led_override[petal] = 120
+                    self.led_override[petal] = 50
                     if event.time > self.laststreak:
                         self.streak += 1
                         self.laststreak = event.time
@@ -374,6 +405,8 @@ class SongView(BaseView):
                             print(self.time - event.time)
                     self.petals[petal] = event
                     self.good = 1.0
+                    self.last_played = event.time
+                    media.set_volume(1.0)
 
             if not pressed:
                 self.petals[petal] = None
@@ -384,6 +417,7 @@ class SongView(BaseView):
                 utils.petal_leds(petal, d)
 
         leds.update()
+        #gc.collect()
         #print("think", gc.mem_alloc() - mem)
 
     def on_enter(self, vm: Optional[ViewManager]) -> None:
@@ -393,7 +427,8 @@ class SongView(BaseView):
             return
         if self.app:
             media.load(self.app.path + '/sounds/start.mp3')
-            self.app.blm.volume = 10000
+            utils.volume(self.app, 10000)
+        leds.set_slew_rate(238)
             
     def on_enter_done(self):
         #sys_display.set_mode(sys_display.get_mode() | 512)
@@ -410,7 +445,7 @@ class SongView(BaseView):
         #gc.enable()
 
         if self.app and not self.finished:
-            self.app.blm.volume = 14000
+            utils.volume(self.app, 14000)
             utils.play_back(self.app)
             
         if self.song and not self.started:
diff --git a/songinfo.py b/songinfo.py
index 2a1ec67e536e78d5d94e39398497ec5ad9fb60c7..23d174a317dc5f03e9fca850ce8f3b46b46bab25 100644
--- a/songinfo.py
+++ b/songinfo.py
@@ -3,30 +3,7 @@ import os
 import midi
 import midireader
 
-AMAZING_DIFFICULTY      = 0
-MEDIUM_DIFFICULTY       = 1
-EASY_DIFFICULTY         = 2
-SUPAEASY_DIFFICULTY     = 3
-
-class Difficulty:
-  def __init__(self, id, text):
-    self.id   = id
-    self.text = text
-    
-  def __str__(self):
-    return self.text
-
-  def __repr__(self):
-    return self.text
-
-difficulties = {
-  SUPAEASY_DIFFICULTY: Difficulty(SUPAEASY_DIFFICULTY, "Supaeasy"),
-  EASY_DIFFICULTY:     Difficulty(EASY_DIFFICULTY,     "Easy"),
-  MEDIUM_DIFFICULTY:   Difficulty(MEDIUM_DIFFICULTY,   "Medium"),
-  AMAZING_DIFFICULTY:  Difficulty(AMAZING_DIFFICULTY,  "Amazing"),
-}
-
-noteSet = set(midireader.noteMap.keys())
+from midireader import difficulties, noteSet
 
 class MidiInfoReader(midi.MidiOutStream):
   __slots__ = ("notes", )
diff --git a/utils.py b/utils.py
index d7fb6ae312207187777ce5ee7a3c81cf8e3473ad..2ae4ec26522878544ee612e31a5b01972a275b02 100644
--- a/utils.py
+++ b/utils.py
@@ -3,6 +3,7 @@ import leds
 import random
 import os
 import time
+import sys_bl00mbox
 
 def dim(color, val):
     res = []
@@ -45,25 +46,46 @@ def petal_leds(petal, val, color = None):
             led += 40
         leds.set_rgb(led, *color)
 
+def blm_wake(app, timeout):
+    if not app or not app.loaded: return
+    if app.blm_timeout == 0:
+        sys_bl00mbox.channel_enable(app.blm.channel_num)
+    if timeout > app.blm_timeout:
+        app.blm_timeout = timeout
+
+def blm_timeout(view, delta_ms):
+    app = view.app
+    if not app: return
+    if not view.is_active(): return
+    if app.blm_timeout == 0: return
+    app.blm_timeout -= delta_ms
+    if app.blm_timeout <= 0:
+        sys_bl00mbox.channel_disable(app.blm.channel_num)
+        app.blm_timeout = 0
+
 def play_crunch(app):
     if not app: return
     if not app.crunch_sound:
         return
     app.crunch_sound[random.randint(0, 2)].signals.trigger.start()
+    blm_wake(app, 600)
 
 def play_fiba(app):
     if not app: return
     if not app.fiba_sound:
         return
     app.fiba_sound[random.randint(0, 5)].signals.trigger.start()
+    blm_wake(app, 1400)
 
 def play_go(app):
-    if not app: return
+    if not app or not app.loaded: return
     app.in_sound.signals.trigger.start()
+    blm_wake(app, 1200)
 
 def play_back(app):
-    if not app: return
+    if not app or not app.loaded: return
     app.out_sound.signals.trigger.start()
+    blm_wake(app, 800)
 
 def circle(ctx, x, y, r):
     c = 0.55191502449
@@ -92,3 +114,7 @@ def timed_function(f, *args, **kwargs):
         print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000))
         return result
     return new_func
+
+def volume(app, vol):
+    if app and app.loaded:
+        app.blm.volume = vol