<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Midi Sequencer in Python - Bagaag</title>
	<atom:link href="https://www.bagaag.com/midi-sequencer-in-python/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bagaag.com</link>
	<description></description>
	<lastBuildDate>Sun, 28 Sep 2025 00:52:57 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.bagaag.com/wp-content/uploads/2025/09/cropped-bagaag-favicon-32x32.png</url>
	<title>Midi Sequencer in Python - Bagaag</title>
	<link>https://www.bagaag.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
					<title>Midi Sequencer in Python</title>
					<link>https://www.bagaag.com/midi-sequencer-in-python/</link>
					<comments>https://www.bagaag.com/midi-sequencer-in-python/#respond</comments>
		
		<dc:creator><![CDATA[matt]]></dc:creator>
		<pubDate>Wed, 17 Sep 2025 03:03:15 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[midi]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://www.bagaag.com/?p=70</guid>

					<description><![CDATA[I’ve always thought it would be cool to be able to compose music in code. There are some languages out there that do this, but I was more interested in direct midi programming than in a DSL for composing music. Enter&#160;mido. mido&#160;is a midi library for Python that wraps the lower-level midi library&#160;python-rtmidi&#160;in a friendlier [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>I’ve always thought it would be cool to be able to compose music in code. There are some languages out there that do this, but I was more interested in direct midi programming than in a DSL for composing music. Enter&nbsp;<code>mido</code>.</p>



<span id="more-70"></span>



<p><a href="https://github.com/mido/mido">mido</a>&nbsp;is a midi library for Python that wraps the lower-level midi library&nbsp;<a href="https://pypi.org/project/python-rtmidi/">python-rtmidi</a>&nbsp;in a friendlier API. It can do a lot of things, but I was primarily interested in using code to control a synth in Bitwig Studio. I ended up writing a little step sequencer API. I used to love playing with <a href="https://www.bagaag.com/wp-content/uploads/2025/09/seq303.jpg" target="_blank" rel="noreferrer noopener">Seq 303</a> back in the 90s, and that’s sort of what I had in mind in terms of how to model midi notes into a song. </p>



<p>I started by defining a Note class.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">Python</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># note.py
import mido

class Note:

    # http://bradthemad.org/guitar/tempo_explanation.php
    LENGTHS = {
        'w': 240,
        'h': 120,
        'q': 60,
        'e': 30,
        's': 15,
        't': 7.5,
        'dq': 90,
        'de': 45,
        'ds': 22.5,
        'tq': 40,
        'te': 20,
        'ts': 10
    }

    # what is the equivalent of '1' numeric duration value
    DURATION_MULTIPLIER = LENGTHS['q']

    def __init__(self, value:int, duration, multiplier=1, velocity:int=64):
        self.value = value
        self.duration = duration
        self.multiplier = multiplier
        self.velocity = velocity

    # Converts a note length value like dotted eighth to a value 
    # in seconds based on default or provided bpm tempo. 
    # Length abbrs: w, h, q, e, s, t, dq, de, ds, tq, te, ts 
    # (whole/half/quarter/eight/sixteenth/32nd, dotted/triplet)
    def seconds(self, tempo:int):
        if  type(self.duration) == str:
            if self.duration in Note.LENGTHS:
                len = Note.LENGTHS[self.duration]
                return len * self.multiplier / tempo
            else:
                return 0
        else:
            return self.duration * Note.DURATION_MULTIPLIER / tempo
        
    # Returns mido "note_on" message
    def get_on(self):
        print(f"On {self.value} {self.duration}")
        return mido.Message('note_on', note=self.value, 
          velocity=self.velocity)

    # Returns mido "note_off" message
    def get_off(self):
        print(f"Off {self.value} {self.duration}")
        return mido.Message('note_off', note=self.value)</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># note.py</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> mido</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Note</span><span style="color: #ECEFF4">:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># http://bradthemad.org/guitar/tempo_explanation.php</span></span>
<span class="line"><span style="color: #D8DEE9FF">    LENGTHS </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">w</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">240</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">h</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">120</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">q</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">60</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">e</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">30</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">s</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">15</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">t</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">7.5</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">dq</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">90</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">de</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">45</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">ds</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">22.5</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">tq</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">40</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">te</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">20</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">ts</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># what is the equivalent of '1' numeric duration value</span></span>
<span class="line"><span style="color: #D8DEE9FF">    DURATION_MULTIPLIER </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> LENGTHS</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">q</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">__init__</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">value</span><span style="color: #ECEFF4">:</span><span style="color: #88C0D0">int</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">duration</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">multiplier</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">velocity</span><span style="color: #ECEFF4">:</span><span style="color: #88C0D0">int</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">64</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> value</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> duration</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">multiplier </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> multiplier</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">velocity </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> velocity</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># Converts a note length value like dotted eighth to a value </span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># in seconds based on default or provided bpm tempo. </span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># Length abbrs: w, h, q, e, s, t, dq, de, ds, tq, te, ts </span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># (whole/half/quarter/eight/sixteenth/32nd, dotted/triplet)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">seconds</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tempo</span><span style="color: #ECEFF4">:</span><span style="color: #88C0D0">int</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">str</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> Note</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">LENGTHS</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #88C0D0">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> Note</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">LENGTHS</span><span style="color: #ECEFF4">[</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration</span><span style="color: #ECEFF4">]</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">multiplier </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> tempo</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">else</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">else</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> Note</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">DURATION_MULTIPLIER </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> tempo</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># Returns mido "note_on" message</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_on</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">"On </span><span style="color: #EBCB8B">{</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C"> </span><span style="color: #EBCB8B">{</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">"</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> mido</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">Message</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">note_on</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">note</span><span style="color: #81A1C1">=self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">          </span><span style="color: #D8DEE9">velocity</span><span style="color: #81A1C1">=self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">velocity</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88"># Returns mido "note_off" message</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_off</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">"Off </span><span style="color: #EBCB8B">{</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C"> </span><span style="color: #EBCB8B">{</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">duration</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">"</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> mido</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">Message</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">note_off</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">note</span><span style="color: #81A1C1">=self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value</span><span style="color: #ECEFF4">)</span></span></code></pre></div>



<p>And then a basic sequencer to play them.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">Python</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># sequencer.py
import concurrent
from concurrent.futures import ThreadPoolExecutor
import mido
from threading import Thread
import time

from note import Note

class Step: 
    def __init__(self, value:int, duration:int=1, start_tick:int=0):
        self.enabled = True
        self.start_tick = start_tick
        self.adjust_duration_for_start_tick = True
        self.note = Note(value, duration)

class Sequencer:
    def __init__(self): 
        self.tick_count = 16
        self.tempo = 100
        self.step_length = 60
        self.step_seconds = self.step_length / self.tempo
        # an array of steps played in sequence,
        # nested arrays are chords
        self.steps = []
        # this is system specific
        port_id = 'Virtual Raw MIDI 0-0:VirMIDI 0-0 16:0'
        self.port = mido.open_output(port_id)

    def play(self):
        # using a thread for each note feels heavy-handed,
        # an interesting optimization problem
        with ThreadPoolExecutor(max_workers=5) as executor:
            for ix in range(len(self.steps)):
                step = self.steps[ix]
                if type(step) == Step and step.enabled:
                    print(f"Step {ix+1}: {step.note.value}")
                    self.play_step(executor, step)
                elif type(step) == list:
                    print(f"Step {ix+1}: {self.chord_str(step)}")
                    for substep in step:
                        self.play_step(executor, substep)
                time.sleep(self.step_seconds)

    def play_step(self, executor, step):
        future = executor.submit(note_player, self, step)
        future.add_done_callback(note_finished)

    def chord_str(self, steps):
        return [step.note.value for step in steps]

def note_player(seq:Sequencer, step:Step):
    applied_length = seq.step_length / seq.tempo
    delay_seconds = step.start_tick * ( applied_length ) / seq.tick_count
    note_seconds = step.note.seconds(seq.tempo)
    if delay_seconds &gt; 0:
        time.sleep(delay_seconds)
        if step.adjust_duration_for_start_tick:
            note_seconds = note_seconds - delay_seconds
    seq.port.send(step.note.get_on());
    time.sleep(note_seconds)
    seq.port.send(step.note.get_off());
    return step

def note_finished(future:concurrent.futures.Future):
    print(f"Finished: {future.result().note.value}")
</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># sequencer.py</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> concurrent</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> concurrent</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">futures </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> ThreadPoolExecutor</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> mido</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> threading </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> Thread</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> time</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> note </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> Note</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Step</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">__init__</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">value</span><span style="color: #ECEFF4">:</span><span style="color: #88C0D0">int</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">duration</span><span style="color: #ECEFF4">:</span><span style="color: #88C0D0">int</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">start_tick</span><span style="color: #ECEFF4">:</span><span style="color: #88C0D0">int</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">enabled </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">True</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">start_tick </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> start_tick</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">adjust_duration_for_start_tick </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">True</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">note </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Note</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">value</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> duration</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">class</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Sequencer</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">__init__</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">):</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">tick_count </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">16</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">tempo </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">100</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">step_length </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">60</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">step_seconds </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">step_length </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">tempo</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88"># an array of steps played in sequence,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88"># nested arrays are chords</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">steps </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[]</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88"># this is system specific</span></span>
<span class="line"><span style="color: #D8DEE9FF">        port_id </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">Virtual Raw MIDI 0-0:VirMIDI 0-0 16:0</span><span style="color: #ECEFF4">'</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">port </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> mido</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">open_output</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">port_id</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">play</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88"># using a thread for each note feels heavy-handed,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88"># an interesting optimization problem</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">with</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ThreadPoolExecutor</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">max_workers</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> executor</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> ix </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">range</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">len</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">steps</span><span style="color: #ECEFF4">)):</span></span>
<span class="line"><span style="color: #D8DEE9FF">                step </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">steps</span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9FF">ix</span><span style="color: #ECEFF4">]</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> Step </span><span style="color: #81A1C1">and</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">enabled</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">"Step </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">ix</span><span style="color: #81A1C1">+</span><span style="color: #B48EAD">1</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">: </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">note</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">"</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">play_step</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">executor</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">elif</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">type</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">list</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">"Step </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">ix</span><span style="color: #81A1C1">+</span><span style="color: #B48EAD">1</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">: </span><span style="color: #EBCB8B">{</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">chord_str</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">)</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">"</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> substep </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                        </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">play_step</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">executor</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> substep</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">                time</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">sleep</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">step_seconds</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">play_step</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">executor</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">step</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        future </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> executor</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">submit</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">note_player</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        future</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">add_done_callback</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">note_finished</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">chord_str</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">self</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">steps</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">note</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> step </span><span style="color: #81A1C1">in</span><span style="color: #D8DEE9FF"> steps</span><span style="color: #ECEFF4">]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">note_player</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">seq</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">Sequencer</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">step</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">Step</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">    applied_length </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">step_length </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">tempo</span></span>
<span class="line"><span style="color: #D8DEE9FF">    delay_seconds </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">start_tick </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF"> applied_length </span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">tick_count</span></span>
<span class="line"><span style="color: #D8DEE9FF">    note_seconds </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">note</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">seconds</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">tempo</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> delay_seconds </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">        time</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">sleep</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">delay_seconds</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">adjust_duration_for_start_tick</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">            note_seconds </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> note_seconds </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> delay_seconds</span></span>
<span class="line"><span style="color: #D8DEE9FF">    seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">port</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">send</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">note</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get_on</span><span style="color: #ECEFF4">())</span><span style="color: #D8DEE9">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    time</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">sleep</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">note_seconds</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">port</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">send</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">step</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">note</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">get_off</span><span style="color: #ECEFF4">())</span><span style="color: #D8DEE9">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> step</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">def</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">note_finished</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">future</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">concurrent</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">futures</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">Future</span><span style="color: #ECEFF4">):</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">print</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">f</span><span style="color: #A3BE8C">"Finished: </span><span style="color: #EBCB8B">{</span><span style="color: #D8DEE9FF">future</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">result</span><span style="color: #ECEFF4">().</span><span style="color: #D8DEE9FF">note</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">value</span><span style="color: #EBCB8B">}</span><span style="color: #A3BE8C">"</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span></code></pre></div>



<p>And finally, a little celebratory tune.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">Python</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly># tada.py
from sequencer import Sequencer, Step

step1 = Step(60, 1)
step2 = Step(64, 1)
step3 = Step(67, 1)
step4 = Step(72, 1)

step1a = Step(60, 4, 1)
step2a = Step(64, 4, 2)
step3a = Step(67, 4, 3)
step4a = Step(72, 4, 4)

steps = [step1, step2, step3, step4 ]
steps.append([step1a, step2a, step3a, step4a])

seq = Sequencer()
seq.steps = steps
seq.play()</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># tada.py</span></span>
<span class="line"><span style="color: #81A1C1">from</span><span style="color: #D8DEE9FF"> sequencer </span><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> Sequencer</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> Step</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">step1 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">60</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">step2 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">64</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">step3 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">67</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">step4 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">72</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">step1a </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">60</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">step2a </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">64</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">step3a </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">67</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">step4a </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Step</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">72</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">steps </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[</span><span style="color: #D8DEE9FF">step1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step3</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step4 </span><span style="color: #ECEFF4">]</span></span>
<span class="line"><span style="color: #D8DEE9FF">steps</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">append</span><span style="color: #ECEFF4">([</span><span style="color: #D8DEE9FF">step1a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step2a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step3a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> step4a</span><span style="color: #ECEFF4">])</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">seq </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">Sequencer</span><span style="color: #ECEFF4">()</span></span>
<span class="line"><span style="color: #D8DEE9FF">seq</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">steps </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> steps</span></span>
<span class="line"><span style="color: #D8DEE9FF">seq</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">play</span><span style="color: #ECEFF4">()</span></span></code></pre></div>



<p>Here’s the output of <code>python tada.py</code>.</p>



<pre class="wp-block-code"><code>Step 1: 60
On 60 1
Off 60 1
Finished: 60
Step 2: 64
On 64 1
Step 3: 67
Off 64 1
Finished: 64
On 67 1
Step 4: 72
On 72 1
Off 67 1
Finished: 67
Step 5: [60, 64, 67, 72]
Off 72 1
Finished: 72
On 60 4
On 64 4
On 67 4
On 72 4
Off 60 4
Finished: 60
Off 64 4
Finished: 64
Off 67 4
Finished: 67
Off 72 4
Finished: 72</code></pre>



<p>And here’s what it sounds like running through the Bitwig Organ.</p>



<figure class="wp-block-audio"><audio controls src="https://www.bagaag.com/wp-content/uploads/2025/06/tada.mp3"></audio></figure>



<p>If you want to run this locally, you’ll need a midi device to convert the midi notes into sound. For me, that is Bitwig Studio. It might just work using the built-in software synth on Windows, but I haven’t tried it.</p>



<p>You’ll also need to install some python packages. Here’s the <code>requirements.txt</code>.</p>



<pre class="wp-block-code"><code>mido
python-rtmidi
importlib_metadata</code></pre>



<p>And here are shell commands to create a virtual environment, install these requirements, and run the program (I’m using bash).</p>



<pre class="wp-block-code"><code>mkdir midosequencer
cd midosequencer
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python song.py</code></pre>



<p>This was a fun little project. It was interesting to realize how conceptual music time has to be converted into literal time, down to when each note should stop and start, calculated from tempo and note length — something humans do without thinking about it. It also makes me curious how real sequencers like Bitwig handle concurrency and timing.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bagaag.com/midi-sequencer-in-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://www.bagaag.com/wp-content/uploads/2025/06/tada.mp3" length="29615" type="audio/mpeg" />

			</item>
	</channel>
</rss>
