diff --git a/Readme.md b/Readme.md
index 402d96e..05c2ed2 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,356 +1,130 @@
-# Mono + GTK# + Glade — WSL Setup Guide
-
-## Table of Contents
-- [1. Prerequisites](#1-prerequisites)
-- [2. Install Mono](#2-install-mono)
-- [3. Install GTK# (GTK# 3.0, for Ubuntu 24.04)](#3-install-gtk-gtk-30-for-ubuntu-2404)
-- [4. Install Glade (visual UI designer)](#4-install-glade-visual-ui-designer)
-- [5. Optional: libgdiplus (only if using System.Drawing)](#5-optional-libgdiplus-only-if-using-systemdrawing)
-- [6. Compiling & Running](#6-compiling--running)
-- [7. Minimal Working Examples](#7-minimal-working-examples)
-- [8. Custom Output Names, Targets & Exporting DLLs](#8-custom-output-names-targets--exporting-dlls)
-- [9. Common Errors & Fixes](#9-common-errors--fixes)
-- [10. Notes on Alternatives](#10-notes-on-alternatives)
-
----
-
-## 1. Prerequisites
-- Windows 11 (or updated Windows 10) with WSL2 and **WSLg** enabled for GUI support
-- Ubuntu 24.04 (noble) or similar WSL distro
-
-Check WSLg is active:
-```bash
-echo $DISPLAY
-```
-Should return something like `:0`. If empty, GUI apps won't display.
-
----
-
-## 2. Install Mono
-
-```bash
-sudo apt update
-sudo apt install mono-complete
-```
-
-Verify:
-```bash
-mono --version
-mcs --version
-```
-
----
-
-## 3. Install GTK# (GTK# 3.0, for Ubuntu 24.04)
-
-> Note: `gtk-sharp2` is **not available** on Ubuntu 24.04 (noble). Use `gtk-sharp3` instead.
-
-```bash
-sudo add-apt-repository universe
-sudo apt update
-sudo apt install gtk-sharp3
-```
-
-Verify the package is registered:
-```bash
-pkg-config --list-all | grep gtk-sharp
-```
-Expected output:
-gtk-sharp-3.0 Gtk - Gtk
----
-
-## 4. Install Glade (visual UI designer)
-
-```bash
-sudo apt install glade
-```
-
-Launch it:
-```bash
-glade
-```
-Design your UI visually, then save as `yourfile.glade` (XML format).
-
----
-
-## 5. Optional: libgdiplus (only if using System.Drawing)
-
-Only needed if your code uses `System.Drawing.Bitmap`, `Graphics`, etc. (not required for plain GTK#/Glade apps):
-
-```bash
-sudo apt install libgdiplus
-```
-
----
-
-## 6. Compiling & Running
-
-### Plain console C# program
-```bash
-mcs myprogram.cs
-mono myprogram.exe
-```
-
-### GTK# 3.0 program (no Glade)
-```bash
-mcs -pkg:gtk-sharp-3.0 myapp.cs
-mono myapp.exe
-```
-
-### GTK# 3.0 program using a Glade file
-```bash
-mcs -pkg:gtk-sharp-3.0 -pkg:glade-sharp-3.0 myapp.cs
-mono myapp.exe
-```
-Make sure the `.glade` file referenced in code sits in the same folder (or update the path in `new Builder("...")`).
-
----
-
-## 7. Minimal Working Examples
-
-### Hello World (console)
-```csharp
-using System;
-
-class Hello {
- static void Main() {
- Console.WriteLine("Hello from Mono in WSL!");
- }
-}
-```
-```bash
-mcs hello.cs
-mono hello.exe
-```
-
-### Hello World (GTK# window, no Glade)
-```csharp
-using System;
-using Gtk;
-
-class GtkCheck {
- static void Main() {
- Application.Init();
- var win = new Window("Hello GTK#3");
- win.SetDefaultSize(300, 200);
- win.DeleteEvent += (o, args) => Application.Quit();
-
- var button = new Button("Click me");
- button.Clicked += (o, args) => Console.WriteLine("Clicked!");
- win.Add(button);
-
- win.ShowAll();
- Application.Run();
- }
-}
-```
-```bash
-mcs -pkg:gtk-sharp-3.0 gtkcheck.cs
-mono gtkcheck.exe
-```
-
-### Loading a UI built in Glade
-```csharp
-using System;
-using Gtk;
-
-class Program {
- static void Main() {
- Application.Init();
- var builder = new Builder("myui.glade");
- builder.Autoconnect(new Program());
-
- var win = (Window)builder.GetObject("window1");
- win.DeleteEvent += (o, args) => Application.Quit();
- win.ShowAll();
-
- Application.Run();
- }
-}
-```
-```bash
-mcs -pkg:gtk-sharp-3.0 -pkg:glade-sharp-3.0 program.cs
-mono program.exe
-```
-
----
-
-## 8. Custom Output Names, Targets & Exporting DLLs
-
-By default, `mcs file.cs` names the output after the source file (`file.exe`). You can control this with `-out:` and change what kind of binary is produced with `-target:`.
-
-### 8.1 Custom output name
-```bash
-mcs -pkg:gtk-sharp-3.0 Program.cs -out:MyCustomApp.exe
-```
-Run it the same way:
-```bash
-mono MyCustomApp.exe
-```
-
-### 8.2 `-target` options
-| Target | Produces | Notes |
-|---|---|---|
-| `exe` (default) | Console executable | Shows a console window when run on Windows |
-| `winexe` | Windows GUI executable | No console window — correct choice for GTK#/Glade GUI apps distributed on Windows |
-| `library` | `.dll` class library | No `Main` entry point required to run directly; used by other programs |
-| `module` | `.netmodule` | Rarely used; for combining into a single assembly later |
-
-Your example, building a windowed GUI executable with a custom name:
-```bash
-mcs -target:winexe -pkg:gtk-sharp-3.0 Program.cs -out:programwin.exe
-```
-This produces `programwin.exe`, which on Windows will run without popping up a console window alongside your GTK window.
-
-### 8.3 Exporting a DLL
-
-If you want to package reusable code (helper classes, business logic, etc.) as a library instead of a standalone app:
-
-```bash
-mcs -target:library Program.cs -out:MyLibrary.dll
-```
-
-- No `Main()` method is required in a `library` target (though it's fine if one class in your project has one — it just won't be used as an entry point for the DLL itself).
-- This creates `MyLibrary.dll`, a Mono/.NET assembly that other C# programs can reference.
-
-### 8.4 Using a DLL in another program
-
-Suppose `MyLibrary.dll` contains:
-```csharp
-// MyLibrary.cs
-namespace MyLib {
- public class Greeter {
- public string Greet(string name) => $"Hello, {name}!";
- }
-}
-```
-Compiled with:
-```bash
-mcs -target:library MyLibrary.cs -out:MyLibrary.dll
-```
-
-Then in a separate consumer program:
-```csharp
-// ConsumerApp.cs
-using System;
-using MyLib;
-
-class ConsumerApp {
- static void Main() {
- var greeter = new Greeter();
- Console.WriteLine(greeter.Greet("World"));
- }
-}
-```
-
-Compile it while referencing the DLL with `-r:`:
-```bash
-mcs ConsumerApp.cs -r:MyLibrary.dll -out:ConsumerApp.exe
-```
-
-Run it (make sure `MyLibrary.dll` is in the same folder as `ConsumerApp.exe`, or on Mono's library search path):
-```bash
-mono ConsumerApp.exe
-```
-
-### 8.5 Combining `-target:library` with GTK# packages
-If your DLL itself uses GTK# types (e.g., a shared custom widget), include the package flag when building the library too:
-```bash
-mcs -target:library -pkg:gtk-sharp-3.0 MyGtkWidgets.cs -out:MyGtkWidgets.dll
-```
-And reference both the package and the DLL when compiling the consumer:
-```bash
-mcs -pkg:gtk-sharp-3.0 ConsumerApp.cs -r:MyGtkWidgets.dll -out:ConsumerApp.exe
-```
-
-### 8.6 Quick reference
-```bash
-# Console exe, custom name
-mcs Program.cs -out:myapp.exe
-
-# Windowed (no console) exe, custom name
-mcs -target:winexe -pkg:gtk-sharp-3.0 Program.cs -out:programwin.exe
-
-# Class library (DLL)
-mcs -target:library Library.cs -out:MyLibrary.dll
-
-# Program referencing that DLL
-mcs Consumer.cs -r:MyLibrary.dll -out:Consumer.exe
-```
-
-### 8.7 Running the compiled .exe on Windows (outside WSL)
-
-Compiling in WSL produces a `.exe` that targets the .NET/Mono runtime — it is **not** a native Windows binary, and it will not run on Windows by itself. Two things are needed:
-
-**1. Install a runtime on the Windows machine**
-
-Pick one:
-- **Mono runtime for Windows** — install the [Mono for Windows](https://www.mono-project.com/download/stable/) package so `.exe` files built with `mcs` can run via the Mono runtime. After install, you can either double-click the `.exe` (Mono associates itself with `.exe` files) or run it explicitly:
-```powershell
- mono programwin.exe
-```
-- **.NET Framework / .NET runtime** — for simple GTK#-free console apps, the .exe may also run under an installed .NET runtime, but GTK# apps specifically require Mono's GTK# libraries, so the Mono for Windows install is the reliable option.
-
-**2. Copy the required DLLs alongside the .exe**
-
-Your compiled `.exe` references managed DLLs at runtime (not just at compile time). Anything you referenced with `-r:` or `-pkg:` must physically travel with the `.exe`:
-
-- Any custom library you built, e.g. `MyLibrary.dll` or `MyGtkWidgets.dll`
-- GTK# binding assemblies your app depends on (typically already provided by installing Mono for Windows, since it bundles the GTK# runtime — but if you used a nonstandard package, copy its DLL too)
-- Your `.glade` file, if the app loads one via `Builder("myui.glade")` — this isn't a DLL but is just as required; it must sit next to the `.exe` at the same relative path your code expects
-
-Minimum folder layout to copy over to Windows:
-programwin.exe
-MyLibrary.dll (any custom DLLs you referenced with -r:)
-myui.glade (if using Glade)
-
-**Common pitfall:** a program that runs fine in WSL but fails on Windows with `FileNotFoundException` or `Could not load file or assembly` almost always means a referenced DLL (or the `.glade` file) wasn't copied over, or Mono for Windows isn't installed.
-
----
-
-## 9. Common Errors & Fixes
-
-| Error | Cause | Fix |
-|---|---|---|
-| `File does not contain a valid CIL image` | Ran `mono` on `.cs` source instead of compiled `.exe` | Compile first: `mcs file.cs`, then `mono file.exe` |
-| `CS0246: type or namespace 'Gtk' could not be found` | Missing package reference during compile | Add `-pkg:gtk-sharp-3.0` to `mcs` command |
-| `CS0103: name 'Console' does not exist` | Missing `using System;` | Add `using System;` at top of file |
-| `Unable to locate package gtk-sharp2` | Package dropped in Ubuntu 24.04 | Use `gtk-sharp3` instead |
-| `DllNotFoundException: libgdiplus` | Code uses `System.Drawing` without the lib installed | `sudo apt install libgdiplus` |
-| `Could not load file or assembly 'MyLibrary.dll'` | DLL not in same folder / not found | Place DLL next to the `.exe`, or set `MONO_PATH` |
-| `FileNotFoundException` / `Could not load file or assembly` (on Windows) | Runtime not installed, or referenced DLL/.glade not copied alongside the .exe | Install Mono for Windows; copy all `-r:` DLLs and `.glade` files into the same folder as the `.exe` |
-
----
-
-## 10. Notes on Alternatives
-
-GTK# is a legacy, lightly-maintained binding. For new projects, consider:
-- **Avalonia UI** — modern, XAML-based, cross-platform, actively maintained
-```bash
- sudo apt install dotnet-sdk-8.0
- dotnet new install Avalonia.Templates
- dotnet new avalonia.app -o MyApp
-```
-
-Use GTK#/Mono/Glade for legacy projects or learning; use Avalonia + `dotnet` for anything new and long-term.
-
-
-Personal note:
-
-Compile note:
- to compile the cs file
- mcs NAME_OF_THE_FILE.cs
- for GTK appilcation
- mcs -pkg:gtk-sharp-3.0 NAME_OF_THE_FILE.cs
- custom output name / windowed exe
- mcs -target:winexe -pkg:gtk-sharp-3.0 NAME_OF_THE_FILE.cs -out:CUSTOM_NAME.exe
- export as DLL
- mcs -target:library NAME_OF_THE_FILE.cs -out:CUSTOM_NAME.dll
- use a DLL in another program
- mcs Consumer.cs -r:CUSTOM_NAME.dll -out:Consumer.exe
-
-
-
-to run note:
- same for all cases
- mono NAME_OF_THE_FILE.exe
\ No newline at end of file
+# Audio Test Bundle
+
+Standalone harness for verifying the OpenAL playback path used by the EARS
+Linux build. Plays a WAV twice — once through `paplay` (reference), once
+through OpenAL via OpenTK — so a bad file, a bad parser and a bad audio
+backend can be told apart.
+
+## Contents
+
+| File | Purpose |
+|---|---|
+| `altest.exe` | the test program |
+| `OpenTK.dll` | managed OpenAL binding |
+| `OpenTK.dll.config` | dllmap: `openal32.dll` → `libopenal.so.1` |
+| `alsoft.conf` | OpenAL Soft settings (backend, resampler, buffers) |
+| `sound/*.wav` | test assets |
+| `src/altest.cs`, `src/WavFile.cs` | sources, only needed to rebuild |
+
+`OpenTK.dll` and `OpenTK.dll.config` must sit **next to `altest.exe`**. Mono
+resolves assemblies relative to the executable, not the working directory.
+A missing `.config` produces `DllNotFoundException: openal32.dll` on Linux,
+which reads like nonsense until you know what it means.
+
+## Install
+
+```bash
+sudo apt install mono-runtime libmono-system-drawing4.0-cil \
+ libopenal1 openal-info pulseaudio-utils sox
+```
+
+`libmono-system-drawing4.0-cil` is easy to miss. OpenTK's net45 build
+references System.Drawing even though the audio path never touches it.
+
+Add `mono-mcs` only if rebuilding on this machine.
+
+## Run
+
+```bash
+cd audiotest
+export ALSOFT_CONF=$PWD/alsoft.conf
+
+soxi sound/SND200.wav # what the file actually is
+paplay sound/SND200.wav # reference playback
+mono ./altest.exe sound/SND200.wav
+mono ./altest.exe sound/SND200.wav 0.5 # optional gain, 0..1
+```
+
+`ALSOFT_CONF` is required. Without it OpenAL only reads `~/.alsoftrc`, which
+won't exist on a fresh machine, and the bundled settings are ignored silently.
+
+Verbose mixer log:
+
+```bash
+ALSOFT_LOGLEVEL=3 mono ./altest.exe sound/SND200.wav 2>&1 | \
+ grep -E "backend|Post-start|underrun|Error|resampler|Created device"
+```
+
+## Reading the result
+
+| Symptom | Meaning |
+|---|---|
+| Clean in both | audio path is good |
+| Clean in `paplay`, bad in `altest` | backend or resampler config — check the log |
+| Bad in both | source file, or the sound device itself |
+| Bad at gain 1.0, clean at 0.5 | clipping; cap gain at 0.85 in `AudioEngine.SetGain` |
+| `DllNotFoundException` | `OpenTK.dll.config` missing next to the exe |
+
+Key log lines:
+
+- `Initialized backend "pulse"` — which backend won
+- `Post-start: Stereo, Float32, 44100hz, 882 / 2646 buffer` — negotiated rate
+ and buffer. Small buffers on a slow transport cause periodic ticks.
+- `Created device ... "RDP Sink"` — under WSL this is the WSLg bridge, not
+ real hardware. Jitter here is usually the transport and disappears on the
+ target device. Don't tune against it.
+
+Assets are 11025 Hz mono. Against a 44100 or 48000 Hz device everything is
+resampled; `bsinc24` in `alsoft.conf` handles this well. If a future device
+negotiates a rate that isn't an integer multiple, pre-converting the assets
+removes the question entirely:
+
+```bash
+sox in.wav -r 48000 out.wav
+```
+
+## Sound comes out the wrong device
+
+Common on the tablet, where HDMI wins the default.
+
+```bash
+pactl list short sinks # what exists right now
+wpctl status # default is marked with *
+```
+
+Set the default **by name**, not by node ID:
+
+```bash
+pactl set-default-sink alsa_output.platform-cht-bsw-rt5645.HiFi__Speaker__sink
+```
+
+Node IDs are not stable. UCM destroys and recreates the built-in sink every
+time the headphone jack is plugged or unplugged, and the new node gets a new
+ID. An ID captured a minute ago is probably already dead — this looks like a
+sink "disappearing" but is normal behaviour. HDMI keeps a stable ID precisely
+because nothing switches it, which is why it tends to win by default.
+
+The durable fix for a kiosk is to remove HDMI from the running: `pavucontrol`
+→ Configuration → HDMI card → **Off**. This persists across reboots
+(WirePlumber stores card profiles in `~/.local/state/wireplumber/`). With
+HDMI gone, whichever built-in sink exists is the only candidate and jack
+switching just works.
+
+Note: under PipeWire, `/etc/pulse/default.pa` and `~/.config/pulse/default.pa`
+are **ignored**. An old config there will look like it should work while doing
+nothing. The live state is `~/.local/state/wireplumber/default-nodes`.
+
+If a sink seems missing, restart the stack before assuming hardware failure:
+
+```bash
+systemctl --user restart wireplumber pipewire pipewire-pulse
+```
+
+## Rebuilding
+
+```bash
+mcs src/altest.cs src/WavFile.cs -r:OpenTK.dll -out:altest.exe
+```
+
+Keep `altest.cs` out of the main program's `*.cs` glob — two `Main` methods
+in one build is a duplicate-entry-point error.
\ No newline at end of file
diff --git a/ReadmeQuick.md b/ReadmeQuick.md
index f227bb0..76071ef 100644
--- a/ReadmeQuick.md
+++ b/ReadmeQuick.md
@@ -1,17 +1,17 @@
-### 8.6 Quick reference
-```bash
-# Console exe, custom name
-mcs Program.cs -out:myapp.exe
-
-# Console exe, custom name
-mcs -pkg:gtk-sharp-3.0 Program.cs -out:programwin.exe
-
-# Windowed (no console) exe, custom name
-mcs -target:winexe -pkg:gtk-sharp-3.0 Program.cs -out:programwin.exe
-
-# Class library (DLL)
-mcs -target:library Library.cs -out:MyLibrary.dll
-
-# Program referencing that DLL
-mcs Consumer.cs -r:MyLibrary.dll -out:Consumer.exe
-```
+### 8.6 Quick reference
+```bash
+# Console exe, custom name
+mcs Program.cs -out:myapp.exe
+
+# Console exe, custom name
+mcs -pkg:gtk-sharp-3.0 Program.cs -out:programwin.exe
+
+# Windowed (no console) exe, custom name
+mcs -target:winexe -pkg:gtk-sharp-3.0 Program.cs -out:programwin.exe
+
+# Class library (DLL)
+mcs -target:library Library.cs -out:MyLibrary.dll
+
+# Program referencing that DLL
+mcs Consumer.cs -r:MyLibrary.dll -out:Consumer.exe
+```
diff --git a/audiotest/OpenTK.dll b/audiotest/OpenTK.dll
new file mode 100644
index 0000000..c335751
--- /dev/null
+++ b/audiotest/OpenTK.dll
Binary files differ
diff --git a/audiotest/OpenTK.dll.config b/audiotest/OpenTK.dll.config
new file mode 100644
index 0000000..7098d39
--- /dev/null
+++ b/audiotest/OpenTK.dll.config
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/audiotest/WavFile.cs b/audiotest/WavFile.cs
new file mode 100644
index 0000000..0ac207b
--- /dev/null
+++ b/audiotest/WavFile.cs
@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+using System.Text;
+using OpenTK.Audio.OpenAL;
+
+public class WavFile
+{
+ public byte[] Data;
+ public ALFormat Format; // Al.FORMAT_*
+ public int SampleRate;
+
+ public static WavFile Load(string path)
+ {
+ using (var fs = File.OpenRead(path))
+ using (var br = new BinaryReader(fs))
+ {
+ if (new string(br.ReadChars(4)) != "RIFF") throw new Exception("Not RIFF: " + path);
+ br.ReadInt32();
+ if (new string(br.ReadChars(4)) != "WAVE") throw new Exception("Not WAVE: " + path);
+
+ short channels = 0, bits = 0;
+ int rate = 0;
+ byte[] data = null;
+
+ while (fs.Position < fs.Length - 8)
+ {
+ string id = new string(br.ReadChars(4));
+ int len = br.ReadInt32();
+
+ if (id == "fmt ")
+ {
+ br.ReadInt16(); // audio format (1 = PCM)
+ channels = br.ReadInt16();
+ rate = br.ReadInt32();
+ br.ReadInt32(); // byte rate
+ br.ReadInt16(); // block align
+ bits = br.ReadInt16();
+ if (len > 16) br.ReadBytes(len - 16);
+ }
+ else if (id == "data")
+ {
+ data = br.ReadBytes(len);
+ }
+ else
+ {
+ br.ReadBytes(len); // skip unknown chunk
+ }
+
+ if ((len & 1) == 1) br.ReadByte(); // chunks are word-aligned
+ }
+
+ if (data == null) throw new Exception("No data chunk: " + path);
+
+ ALFormat fmt;
+ if (channels == 1 && bits == 8) fmt = ALFormat.Mono8;
+ else if (channels == 1 && bits == 16) fmt = ALFormat.Mono16;
+ else if (channels == 2 && bits == 8) fmt = ALFormat.Stereo8;
+ else if (channels == 2 && bits == 16) fmt = ALFormat.Stereo16;
+ else throw new Exception("Unsupported WAV: " + channels + "ch " + bits + "bit");
+
+ return new WavFile { Data = data, Format = fmt, SampleRate = rate };
+ }
+ }
+}
\ No newline at end of file
diff --git a/audiotest/alsoft.conf b/audiotest/alsoft.conf
new file mode 100644
index 0000000..fdbb03b
--- /dev/null
+++ b/audiotest/alsoft.conf
@@ -0,0 +1,6 @@
+[general]
+drivers = pulse,alsa
+resampler = bsinc24
+period_size = 1024
+periods = 4
+output-limiter = true
\ No newline at end of file
diff --git a/audiotest/altest.cs b/audiotest/altest.cs
new file mode 100644
index 0000000..8b812af
--- /dev/null
+++ b/audiotest/altest.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Threading;
+using OpenTK.Audio;
+using OpenTK.Audio.OpenAL;
+
+class AlTest
+{
+ static void Main(string[] args)
+ {
+ if (args.Length < 1)
+ {
+ Console.WriteLine("usage: altest [gain 0..1]");
+ return;
+ }
+ float gain = args.Length > 1 ? float.Parse(args[1]) : 1.0f;
+
+ var ctx = new AudioContext();
+ ctx.MakeCurrent();
+ Console.WriteLine("device: " + AudioContext.CurrentContext.CurrentDevice);
+
+ WavFile w = WavFile.Load(args[0]);
+ Console.WriteLine("{0} {1} Hz {2} bytes", w.Format, w.SampleRate, w.Data.Length);
+
+ int buf = AL.GenBuffer();
+ AL.BufferData(buf, w.Format, w.Data, w.Data.Length, w.SampleRate);
+
+ int src = AL.GenSource();
+ AL.Source(src, ALSourcei.Buffer, buf);
+ AL.Source(src, ALSourcef.Gain, gain);
+ AL.SourcePlay(src);
+
+ ALError e = AL.GetError();
+ if (e != ALError.NoError) Console.WriteLine("AL error: " + AL.GetErrorString(e));
+
+ while (AL.GetSourceState(src) == ALSourceState.Playing)
+ Thread.Sleep(50);
+
+ AL.DeleteSource(src);
+ AL.DeleteBuffer(buf);
+ ctx.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/audiotest/altest.exe b/audiotest/altest.exe
new file mode 100644
index 0000000..283c6d2
--- /dev/null
+++ b/audiotest/altest.exe
Binary files differ
diff --git a/audiotest/build.sh b/audiotest/build.sh
new file mode 100644
index 0000000..e734470
--- /dev/null
+++ b/audiotest/build.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+set -e
+cd "$(dirname "$0")/.."
+
+OUT=audiotest
+rm -rf "$OUT"
+mkdir -p "$OUT/src" "$OUT/sound"
+
+cp altest.cs WavFile.cs "$OUT/src/"
+cp OpenTK.dll OpenTK.dll.config "$OUT/"
+cp bin/linux/sound/SND200.wav "$OUT/sound/"
+cp audiotest_files/{install.sh,run.sh,alsoft.conf} "$OUT/"
+
+mcs "$OUT/src/altest.cs" "$OUT/src/WavFile.cs" \
+ -r:"$OUT/OpenTK.dll" -out:"$OUT/altest.exe"
+
+chmod +x "$OUT"/*.sh
+tar czf audiotest.tar.gz "$OUT"
+echo "built audiotest.tar.gz"
\ No newline at end of file
diff --git a/audiotest/readme.md b/audiotest/readme.md
new file mode 100644
index 0000000..923cf84
--- /dev/null
+++ b/audiotest/readme.md
@@ -0,0 +1,3 @@
+sudo apt install mono-runtime libmono-system-drawing4.0-cil libopenal1 pulseaudio-utils sox
+paplay sound/SND200.wav
+mono ./altest.exe sound/SND200.wav
\ No newline at end of file