"version_check",
 ]
 
+[[package]]
+name = "alsa"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44"
+dependencies = [
+ "alsa-sys",
+ "bitflags",
+ "libc",
+ "nix 0.24.3",
+]
+
+[[package]]
+name = "alsa-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
 [[package]]
 name = "android_system_properties"
 version = "0.1.5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
 name = "cellseq"
 version = "0.1.0"
 dependencies = [
+ "alsa",
  "array2d",
  "eyre",
  "iced",
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
  "phf_shared",
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.9"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
 
 [[package]]
 name = "pin-utils"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
 
 [[package]]
 name = "syn"
-version = "2.0.22"
+version = "2.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
+checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737"
 dependencies = [
  "proc-macro2",
  "quote",
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
 ]
 
 [[package]]
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
  "wasm-bindgen-shared",
 ]
 
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.22",
+ "syn 2.0.23",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "xml-rs"
-version = "0.8.14"
+version = "0.8.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52839dc911083a8ef63efa4d039d1f58b5e409f923e44c80828f206f66e5541c"
+checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336"
 
 iced = { version = "0.9", features = ["canvas", "tokio", "debug"] }
 itertools = "0.10"
 rustc-hash = "1.1"
+alsa = "0.7"
 
+use std::{io::Write, thread::JoinHandle};
+
+use alsa::{
+    rawmidi::{Rawmidi, IO},
+    Direction,
+};
 use cellseq::*;
 
 use iced::{window, Application, Settings};
 
-use eyre::Result;
+use eyre::{eyre, Result};
 use tokio::sync::mpsc::channel;
 
 pub fn main() -> Result<()> {
-    let (midi_snd, _midi_rcv) = channel::<u8>(256);
-
+    let (midi_snd, mut midi_rcv) = channel::<u8>(256);
     let midi = MidiLink::new(midi_snd);
 
+    let midi_sink = Rawmidi::new("virtual", Direction::Playback, false)?;
+
+    let midi_loop: JoinHandle<Result<()>> = std::thread::spawn(move || {
+        let mut midi_io = midi_sink.io();
+        while let Some(byte) = midi_rcv.blocking_recv() {
+            midi_io.write_all(&[byte])?;
+        }
+        Ok(())
+    });
+
     // running the graphics window
     CellSeq::run(Settings {
         antialiasing: true,
         ..Settings::default()
     })?;
 
+    midi_loop.join().map_err(|_| eyre!("join failure"))??;
+
     Ok(())
 }
 
     }
 }
 
+impl Display for Root {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}{}", self.note, self.accidental)
+    }
+}
+
 impl From<Root> for u8 {
     fn from(val: Root) -> Self {
         let n = match val.note {
             RootNote::A => 21,
-            RootNote::B => 22,
-            RootNote::C => 23,
-            RootNote::D => 24,
-            RootNote::E => 25,
-            RootNote::F => 26,
-            RootNote::G => 27,
+            RootNote::B => 23,
+            RootNote::C => 24,
+            RootNote::D => 26,
+            RootNote::E => 28,
+            RootNote::F => 29,
+            RootNote::G => 31,
         };
 
         match val.accidental {
 impl Display for Accidental {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let str = match self {
-            Accidental::Natural => "",
-            Accidental::Sharp => "#",
-            Accidental::Flat => "b",
+            Accidental::Natural => "♮",
+            Accidental::Sharp => "♯",
+            Accidental::Flat => "♭",
         };
         write!(f, "{str}")
     }