snakeware

Python-based Linux distro for x86-64 and RPi
git clone git://squid-tech.com/snakeware.git
Log | Files | Refs | README

commit 2fb5ab3cf7a7980997413ada666ad35f056129fc
parent c7b3cf3f0d9031b5cdc9a1b890560e911da189a2
Author: Josh Moore <jxm5210@g.rit.edu>
Date:   Sat, 20 Jun 2020 12:37:57 -1100

Merge pull request #131 from mdoege/midi

Add Midi
Diffstat:
Asnakewm/apps/fun/midi/README.md | 15+++++++++++++++
Asnakewm/apps/fun/midi/__init__.py | 14++++++++++++++
Asnakewm/apps/fun/midi/goldberg/bwv-988-v01.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v02.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v03.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v04.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v05.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v06.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v07.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v08.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v09.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v10.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v11.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v12.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v13.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v14.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v15.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v16.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v17.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v18.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v19.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v20.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v21.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v22.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v23.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v24.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v25.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v26.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v27.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v28.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v29.mid | 0
Asnakewm/apps/fun/midi/goldberg/bwv-988-v30.mid | 0
Asnakewm/apps/fun/midi/midi.py | 313+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asnakewm/apps/fun/midi/midisnd/midi01.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi02.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi03.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi04.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi05.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi06.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi07.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi08.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi09.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi10.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi11.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi12.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi13.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi14.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi15.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi16.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi17.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi18.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi19.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi20.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi21.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi22.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi23.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi24.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi25.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi26.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi27.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi28.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi29.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi30.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi31.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi32.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi33.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi34.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi35.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi36.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi37.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi38.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi39.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi40.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi41.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi42.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi43.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi44.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi45.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi46.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi47.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi48.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi49.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi50.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi51.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi52.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi53.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi54.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi55.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi56.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi57.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi58.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi59.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi60.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi61.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi62.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi63.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi64.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi65.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi66.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi67.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi68.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi69.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi70.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi71.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi72.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi73.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi74.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi75.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi76.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi77.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi78.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi79.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi80.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi81.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi82.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi83.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi84.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi85.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi86.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi87.ogg | 0
Asnakewm/apps/fun/midi/midisnd/midi88.ogg | 0
121 files changed, 342 insertions(+), 0 deletions(-)

diff --git a/snakewm/apps/fun/midi/README.md b/snakewm/apps/fun/midi/README.md @@ -0,0 +1,15 @@ +# midi + +Midi is a MIDI synthesizer that plays Bach's [Goldberg Variations](https://en.wikipedia.org/wiki/Goldberg_Variations) using PySynth B piano samples. Notes are shown on a scrolling piano roll view as they are played, based on the standard 88 piano keys with the treble at the top. Playback automatically advances to the next song on the list. + +Press the right and left cursor keys to go to the next/previous track. Adjust playback speed with the up and down cursor keys. Press Space to pause playback. + +The Bach MIDI files are from [Mutopia Project](https://www.mutopiaproject.org/) under the Creative Commons Attribution-ShareAlike license. The Python MIDI file reading code is 2-clause BSD-licensed, which is compatible with Snakeware's MIT license. + +# Author + +Martin C. Doege + ++ github: https://github.com/mdoege + ++ date: 19 Jun 2020 diff --git a/snakewm/apps/fun/midi/__init__.py b/snakewm/apps/fun/midi/__init__.py @@ -0,0 +1,14 @@ +from .midi import MIDI + + +def load(manager, params): + """ + Create and launch a new instance of Midi. + """ + # default position + pos = (100, 100) + + if params is not None and len(params) > 0: + pos = params[0] + + MIDI(pos, manager) diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v01.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v01.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v02.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v02.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v03.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v03.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v04.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v04.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v05.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v05.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v06.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v06.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v07.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v07.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v08.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v08.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v09.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v09.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v10.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v10.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v11.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v11.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v12.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v12.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v13.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v13.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v14.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v14.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v15.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v15.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v16.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v16.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v17.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v17.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v18.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v18.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v19.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v19.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v20.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v20.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v21.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v21.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v22.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v22.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v23.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v23.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v24.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v24.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v25.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v25.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v26.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v26.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v27.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v27.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v28.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v28.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v29.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v29.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/goldberg/bwv-988-v30.mid b/snakewm/apps/fun/midi/goldberg/bwv-988-v30.mid Binary files differ. diff --git a/snakewm/apps/fun/midi/midi.py b/snakewm/apps/fun/midi/midi.py @@ -0,0 +1,313 @@ +#!/usr/bin/env python + +# Based on code from https://github.com/osakared/midifile.py +# which appears to be based on +# https://github.com/gasman/jasmid/blob/master/midifile.js + +# Original license: + +""" +Copyright (c) 2014, Thomas J. Webb +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" +import pygame +import pygame_gui +from pygame_gui.elements.ui_image import UIImage + +import struct, time, statistics, glob, os + + +class Note(object): + "Represents a single MIDI note" + + note_names = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] + + def __init__(self, channel, pitch, velocity, start, duration=0): + self.channel = channel + self.pitch = pitch + self.velocity = velocity + self.start = start + self.duration = duration + + def __str__(self): + s = Note.note_names[(self.pitch - 9) % 12] + s += str(self.pitch // 12 - 1) + s += " " + str(self.velocity) + s += " " + str(self.start) + " " + str(self.start + self.duration) + " " + return s + + def get_end(self): + return self.start + self.duration + + +class MidiFile(object): + "Represents the notes in a MIDI file" + + def read_byte(self, file): + return struct.unpack("B", file.read(1))[0] + + def read_variable_length(self, file, counter): + counter -= 1 + num = self.read_byte(file) + + if num & 0x80: + num = num & 0x7F + while True: + counter -= 1 + c = self.read_byte(file) + num = (num << 7) + (c & 0x7F) + if not (c & 0x80): + break + + return (num, counter) + + def __init__(self, file_name): + self.tempo = 120 + try: + file = open(file_name, "rb") + if file.read(4) != b"MThd": + raise Exception("Not a MIDI file") + self.file_name = file_name + size = struct.unpack(">i", file.read(4))[0] + if size != 6: + raise Exception("Unusual MIDI file with non-6 sized header") + self.format = struct.unpack(">h", file.read(2))[0] + self.track_count = struct.unpack(">h", file.read(2))[0] + self.time_division = struct.unpack(">h", file.read(2))[0] + + # Now to fill out the arrays with the notes + self.tracks = [] + for i in range(0, self.track_count): + self.tracks.append([]) + + for nn, track in enumerate(self.tracks): + abs_time = 0.0 + + if file.read(4) != b"MTrk": + raise Exception("Not a valid track") + size = struct.unpack(">i", file.read(4))[0] + + # To keep track of running status + last_flag = None + while size > 0: + delta, size = self.read_variable_length(file, size) + delta /= float(self.time_division) + abs_time += delta + + size -= 1 + flag = self.read_byte(file) + # Sysex messages + if flag == 0xF0 or flag == 0xF7: + # print "Sysex" + while True: + size -= 1 + if self.read_byte(file) == 0xF7: + break + # Meta messages + elif flag == 0xFF: + size -= 1 + type = self.read_byte(file) + if type == 0x2F: # end of track event + self.read_byte(file) + size -= 1 + break + print("Meta: " + str(type)) + length, size = self.read_variable_length(file, size) + message = file.read(length) + # if type not in [0x0, 0x7, 0x20, 0x2F, 0x51, 0x54, 0x58, 0x59, 0x7F]: + print(length, message) + if type == 0x51: # qpm/bpm + # http://www.recordingblogs.com/sa/Wiki?topic=MIDI+Set+Tempo+meta+message + self.tempo = 6e7 / struct.unpack(">i", b"\x00" + message)[0] + print("tempo =", self.tempo, "bpm") + # MIDI messages + else: + if flag & 0x80: + type_and_channel = flag + size -= 1 + param1 = self.read_byte(file) + last_flag = flag + else: + type_and_channel = last_flag + param1 = flag + type = (type_and_channel & 0xF0) >> 4 + channel = type_and_channel & 0xF + if type == 0xC: # detect MIDI program change + print("program change, channel", channel, "=", param1) + continue + size -= 1 + param2 = self.read_byte(file) + + # detect MIDI ons and MIDI offs + if type == 0x9: + track.append(Note(channel, param1, param2, abs_time)) + elif type == 0x8: + for note in reversed(track): + if note.channel == channel and note.pitch == param1: + note.duration = abs_time - note.start + break + + except Exception as e: + print("Cannot parse MIDI file: " + str(e)) + finally: + file.close() + + def __str__(self): + s = "" + for i, track in enumerate(self.tracks): + s += "Track " + str(i + 1) + "\n" + for note in track: + s += str(note) + "\n" + return s + + +RES = 650, 440 +BACKGROUND = 100, 100, 100 +TARGET_FPS = 60 # FPS that PyGame is expcted to run at +PATH = os.path.dirname(os.path.abspath(__file__)) +SONG_DIR = PATH + "/goldberg" + + +def ini(s, res): + "Load samples" + global audio + + audio = {} + for n in range(2, 89): + # samples are numbered with middle C == 39 (i.e. off by one) + audio[n] = pygame.mixer.Sound(PATH + "/midisnd/midi%02u.ogg" % (n - 1)) + audio[n].set_volume(0.2) + + +def load_song(s, res, fn): + "Load song data" + global notes, t, inc, first, last + + notes = [] + first, last = 1e9, -1 + m = MidiFile(fn) + for tn in range(len(m.tracks)): + for n in m.tracks[tn]: + if n.velocity > 0: + tt = int(1000 * n.start) + first = min(first, tt) + last = max(last, tt) + notes.append([n.pitch - 20, tt]) + inc = 20 # advance by this many MIDI time units during each PyGame frame + t = 0 + # print(notes) + + +def play(s, res, fpsfac, tfac): + "Play all notes that should trigger during this PyGame frame" + global t + s.scroll(dx=-2) + pygame.draw.rect(s, BACKGROUND, [RES[0] - 2, 0, 2, RES[1]]) + # apply user tempo selection and FPS adjustment + rinc = int(inc * fpsfac * tfac) + for x, y in notes: + if t <= y - first < t + rinc: + audio[x].stop() + audio[x].play() + pygame.draw.rect(s, (255, 255, 255), [RES[0] - 2, RES[1] - 5 * x, 2, 2]) + # print(y, x) + t += rinc + # end of song? + if t <= last + RES[0] * rinc: + return True + else: + return False + + +class MIDI(pygame_gui.elements.UIWindow): + def __init__(self, pos, manager): + super().__init__( + pygame.Rect(pos, (RES[0] + 32, RES[1] + 60)), + manager=manager, + window_display_title="midi", + object_id="#midi", + resizable=False, + ) + + self.dsurf = UIImage( + pygame.Rect((0, 0), RES), + pygame.Surface(RES).convert(), + manager=manager, + container=self, + parent_element=self, + ) + self.screen = pygame.Surface(RES) + self.screen.fill(BACKGROUND) + pygame.mixer.init() + ini(self.screen, RES) + self.calib = 10 + self.samp = [] + self.last = 0 + self.mlist = sorted(glob.glob(SONG_DIR + "/*.mid")) + self.mselect = 0 + load_song(self.screen, RES, self.mlist[self.mselect]) + self.tempo = 1 + self.paused = False + + def process_event(self, event): + super().process_event(event) + if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT: + self.mselect += 1 + self.mselect = self.mselect % len(self.mlist) + load_song(self.screen, RES, self.mlist[self.mselect]) + if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT: + self.mselect -= 1 + self.mselect = self.mselect % len(self.mlist) + load_song(self.screen, RES, self.mlist[self.mselect]) + if event.type == pygame.KEYDOWN and event.key == pygame.K_UP: + self.tempo += 0.05 + if event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN: + self.tempo -= 0.05 + if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: + self.paused = not self.paused + + def update(self, delta): + super().update(delta) + # measure FPS for automatic adjustment + if self.calib > 0: + f = 1 / (time.time() - self.last) + self.last = time.time() + self.calib -= 1 + self.samp.append(f) + self.fps = statistics.median(self.samp) + print("FPS", self.fps) + return + self.tempo = max(0.1, min(3, self.tempo)) + fn = self.mlist[self.mselect].split("/")[-1] + super().set_display_title("midi (%s, tempo %.2f)" % (fn, self.tempo)) + if self.paused: + return + # play notes + if not play(self.screen, RES, TARGET_FPS / self.fps, self.tempo): + # advance to next song in playlist + self.mselect += 1 + self.mselect = self.mselect % len(self.mlist) + load_song(self.screen, RES, self.mlist[self.mselect]) + + self.dsurf.image.blit(self.screen, (0, 0)) diff --git a/snakewm/apps/fun/midi/midisnd/midi01.ogg b/snakewm/apps/fun/midi/midisnd/midi01.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi02.ogg b/snakewm/apps/fun/midi/midisnd/midi02.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi03.ogg b/snakewm/apps/fun/midi/midisnd/midi03.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi04.ogg b/snakewm/apps/fun/midi/midisnd/midi04.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi05.ogg b/snakewm/apps/fun/midi/midisnd/midi05.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi06.ogg b/snakewm/apps/fun/midi/midisnd/midi06.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi07.ogg b/snakewm/apps/fun/midi/midisnd/midi07.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi08.ogg b/snakewm/apps/fun/midi/midisnd/midi08.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi09.ogg b/snakewm/apps/fun/midi/midisnd/midi09.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi10.ogg b/snakewm/apps/fun/midi/midisnd/midi10.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi11.ogg b/snakewm/apps/fun/midi/midisnd/midi11.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi12.ogg b/snakewm/apps/fun/midi/midisnd/midi12.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi13.ogg b/snakewm/apps/fun/midi/midisnd/midi13.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi14.ogg b/snakewm/apps/fun/midi/midisnd/midi14.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi15.ogg b/snakewm/apps/fun/midi/midisnd/midi15.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi16.ogg b/snakewm/apps/fun/midi/midisnd/midi16.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi17.ogg b/snakewm/apps/fun/midi/midisnd/midi17.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi18.ogg b/snakewm/apps/fun/midi/midisnd/midi18.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi19.ogg b/snakewm/apps/fun/midi/midisnd/midi19.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi20.ogg b/snakewm/apps/fun/midi/midisnd/midi20.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi21.ogg b/snakewm/apps/fun/midi/midisnd/midi21.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi22.ogg b/snakewm/apps/fun/midi/midisnd/midi22.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi23.ogg b/snakewm/apps/fun/midi/midisnd/midi23.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi24.ogg b/snakewm/apps/fun/midi/midisnd/midi24.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi25.ogg b/snakewm/apps/fun/midi/midisnd/midi25.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi26.ogg b/snakewm/apps/fun/midi/midisnd/midi26.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi27.ogg b/snakewm/apps/fun/midi/midisnd/midi27.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi28.ogg b/snakewm/apps/fun/midi/midisnd/midi28.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi29.ogg b/snakewm/apps/fun/midi/midisnd/midi29.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi30.ogg b/snakewm/apps/fun/midi/midisnd/midi30.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi31.ogg b/snakewm/apps/fun/midi/midisnd/midi31.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi32.ogg b/snakewm/apps/fun/midi/midisnd/midi32.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi33.ogg b/snakewm/apps/fun/midi/midisnd/midi33.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi34.ogg b/snakewm/apps/fun/midi/midisnd/midi34.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi35.ogg b/snakewm/apps/fun/midi/midisnd/midi35.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi36.ogg b/snakewm/apps/fun/midi/midisnd/midi36.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi37.ogg b/snakewm/apps/fun/midi/midisnd/midi37.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi38.ogg b/snakewm/apps/fun/midi/midisnd/midi38.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi39.ogg b/snakewm/apps/fun/midi/midisnd/midi39.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi40.ogg b/snakewm/apps/fun/midi/midisnd/midi40.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi41.ogg b/snakewm/apps/fun/midi/midisnd/midi41.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi42.ogg b/snakewm/apps/fun/midi/midisnd/midi42.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi43.ogg b/snakewm/apps/fun/midi/midisnd/midi43.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi44.ogg b/snakewm/apps/fun/midi/midisnd/midi44.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi45.ogg b/snakewm/apps/fun/midi/midisnd/midi45.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi46.ogg b/snakewm/apps/fun/midi/midisnd/midi46.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi47.ogg b/snakewm/apps/fun/midi/midisnd/midi47.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi48.ogg b/snakewm/apps/fun/midi/midisnd/midi48.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi49.ogg b/snakewm/apps/fun/midi/midisnd/midi49.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi50.ogg b/snakewm/apps/fun/midi/midisnd/midi50.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi51.ogg b/snakewm/apps/fun/midi/midisnd/midi51.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi52.ogg b/snakewm/apps/fun/midi/midisnd/midi52.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi53.ogg b/snakewm/apps/fun/midi/midisnd/midi53.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi54.ogg b/snakewm/apps/fun/midi/midisnd/midi54.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi55.ogg b/snakewm/apps/fun/midi/midisnd/midi55.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi56.ogg b/snakewm/apps/fun/midi/midisnd/midi56.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi57.ogg b/snakewm/apps/fun/midi/midisnd/midi57.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi58.ogg b/snakewm/apps/fun/midi/midisnd/midi58.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi59.ogg b/snakewm/apps/fun/midi/midisnd/midi59.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi60.ogg b/snakewm/apps/fun/midi/midisnd/midi60.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi61.ogg b/snakewm/apps/fun/midi/midisnd/midi61.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi62.ogg b/snakewm/apps/fun/midi/midisnd/midi62.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi63.ogg b/snakewm/apps/fun/midi/midisnd/midi63.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi64.ogg b/snakewm/apps/fun/midi/midisnd/midi64.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi65.ogg b/snakewm/apps/fun/midi/midisnd/midi65.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi66.ogg b/snakewm/apps/fun/midi/midisnd/midi66.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi67.ogg b/snakewm/apps/fun/midi/midisnd/midi67.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi68.ogg b/snakewm/apps/fun/midi/midisnd/midi68.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi69.ogg b/snakewm/apps/fun/midi/midisnd/midi69.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi70.ogg b/snakewm/apps/fun/midi/midisnd/midi70.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi71.ogg b/snakewm/apps/fun/midi/midisnd/midi71.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi72.ogg b/snakewm/apps/fun/midi/midisnd/midi72.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi73.ogg b/snakewm/apps/fun/midi/midisnd/midi73.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi74.ogg b/snakewm/apps/fun/midi/midisnd/midi74.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi75.ogg b/snakewm/apps/fun/midi/midisnd/midi75.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi76.ogg b/snakewm/apps/fun/midi/midisnd/midi76.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi77.ogg b/snakewm/apps/fun/midi/midisnd/midi77.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi78.ogg b/snakewm/apps/fun/midi/midisnd/midi78.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi79.ogg b/snakewm/apps/fun/midi/midisnd/midi79.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi80.ogg b/snakewm/apps/fun/midi/midisnd/midi80.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi81.ogg b/snakewm/apps/fun/midi/midisnd/midi81.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi82.ogg b/snakewm/apps/fun/midi/midisnd/midi82.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi83.ogg b/snakewm/apps/fun/midi/midisnd/midi83.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi84.ogg b/snakewm/apps/fun/midi/midisnd/midi84.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi85.ogg b/snakewm/apps/fun/midi/midisnd/midi85.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi86.ogg b/snakewm/apps/fun/midi/midisnd/midi86.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi87.ogg b/snakewm/apps/fun/midi/midisnd/midi87.ogg Binary files differ. diff --git a/snakewm/apps/fun/midi/midisnd/midi88.ogg b/snakewm/apps/fun/midi/midisnd/midi88.ogg Binary files differ.