Code Examples
Practical examples demonstrating OwnAudioSharp's capabilities. From simple playback to advanced real-time processing.
🎵 Audio Player Beginner
Complete console-based audio player with interactive controls
View Example →🎛️ Effect Processor Intermediate
Apply and chain multiple audio effects with real-time control
View Example →🔄 Real-Time Synthesizer Advanced
Generate and process audio in real-time with effects
View Example →Simple Audio Playback
The most basic example - loading and playing an audio file.
using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading.Tasks;
class BasicPlayback
{
static async Task Main(string[] args)
{
try
{
// Initialize OwnAudio
OwnAudio.Initialize();
var sourceManager = SourceManager.Instance;
// Load an audio file
await sourceManager.AddOutputSource("music.mp3", "MyTrack");
Console.WriteLine($"Loaded: {sourceManager["MyTrack"].Duration}");
// Start playback
sourceManager.Play();
Console.WriteLine("Playing... Press any key to stop.");
Console.ReadKey();
// Stop and cleanup
sourceManager.Stop();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
finally
{
OwnAudio.Free();
}
}
}
Multiple Audio Sources
Mix multiple audio sources with individual volume control.
using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading.Tasks;
class AudioMixer
{
static async Task Main(string[] args)
{
try
{
OwnAudio.Initialize();
var sourceManager = SourceManager.Instance;
// Add multiple sources
await sourceManager.AddOutputSource("background.mp3", "Background");
await sourceManager.AddOutputSource("drums.wav", "Drums");
await sourceManager.AddOutputSource("bass.wav", "Bass");
// Set individual volumes
sourceManager["Background"].Volume = 0.6f; // 60% background music
sourceManager["Drums"].Volume = 0.8f; // 80% drums
sourceManager["Bass"].Volume = 0.7f; // 70% bass
// Start mixed playback
sourceManager.Play();
// Interactive volume control
await RunVolumeControl(sourceManager);
}
finally
{
OwnAudio.Free();
}
}
static async Task RunVolumeControl(SourceManager manager)
{
while (manager.IsPlaying)
{
Console.WriteLine("\nVolume Control:");
Console.WriteLine("1. Background 2. Drums 3. Bass 4. Quit");
var key = Console.ReadKey().KeyChar;
if (key == '4') break;
string sourceName = key switch
{
'1' => "Background",
'2' => "Drums",
'3' => "Bass",
_ => null
};
if (sourceName != null)
{
Console.Write($"\nNew volume for {sourceName} (0.0-1.0): ");
if (float.TryParse(Console.ReadLine(), out float volume))
{
manager[sourceName].Volume = Math.Clamp(volume, 0f, 1f);
Console.WriteLine($"{sourceName} volume set to {volume:F2}");
}
}
}
}
}
Audio Recording
Record audio from microphone to file with configurable bit depth.
using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading.Tasks;
class AudioRecorder
{
static async Task Main(string[] args)
{
try
{
OwnAudio.Initialize();
var sourceManager = SourceManager.Instance;
// Add input source (microphone)
var inputSource = await sourceManager.AddInputSource("Microphone");
Console.WriteLine("Microphone ready for recording.");
Console.WriteLine("Press ENTER to start recording...");
Console.ReadLine();
// Start recording to file (16-bit WAV)
string outputFile = $"recording_{DateTime.Now:yyyyMMdd_HHmmss}.wav";
sourceManager.Play(outputFile, 16);
Console.WriteLine($"🔴 Recording to {outputFile}");
Console.WriteLine("Press ENTER to stop recording...");
Console.ReadLine();
// Stop recording
sourceManager.Stop();
Console.WriteLine($"✅ Recording saved: {outputFile}");
// Optional: Playback the recorded file
Console.WriteLine("Play back recording? (y/n)");
if (Console.ReadKey().KeyChar == 'y')
{
await PlaybackRecording(outputFile);
}
}
catch (Exception ex)
{
Console.WriteLine($"Recording error: {ex.Message}");
}
finally
{
OwnAudio.Free();
}
}
static async Task PlaybackRecording(string filePath)
{
try
{
var sourceManager = SourceManager.Instance;
// Clear previous sources
sourceManager.Sources.Clear();
// Load and play recording
await sourceManager.AddOutputSource(filePath, "Recording");
sourceManager.Play();
Console.WriteLine($"\n🎵 Playing back recording ({sourceManager["Recording"].Duration})");
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
sourceManager.Stop();
}
catch (Exception ex)
{
Console.WriteLine($"Playback error: {ex.Message}");
}
}
}
Applying Audio Effects
Apply professional audio effects like reverb, delay, and compression.
using Ownaudio;
using Ownaudio.Sources;
using Ownaudio.Processors;
using System;
using System.Threading.Tasks;
class EffectProcessor
{
private static SourceManager sourceManager;
static async Task Main(string[] args)
{
try
{
OwnAudio.Initialize();
sourceManager = SourceManager.Instance;
// Load audio file
await sourceManager.AddOutputSource("audio.mp3", "Track");
sourceManager.Play();
Console.WriteLine("🎛️ Effect Processor");
Console.WriteLine("Track loaded and playing...");
await RunEffectMenu();
}
finally
{
OwnAudio.Free();
}
}
static async Task RunEffectMenu()
{
while (sourceManager.IsPlaying)
{
Console.WriteLine("\n=== Audio Effects ===");
Console.WriteLine("1. Hall Reverb 2. Room Reverb");
Console.WriteLine("3. Echo Delay 4. Ping Pong Delay");
Console.WriteLine("5. Compressor 6. Equalizer");
Console.WriteLine("7. Clear Effects 8. Exit");
Console.Write("Choose effect: ");
var choice = Console.ReadKey().KeyChar;
Console.WriteLine();
switch (choice)
{
case '1': ApplyHallReverb(); break;
case '2': ApplyRoomReverb(); break;
case '3': ApplyEchoDelay(); break;
case '4': ApplyPingPongDelay(); break;
case '5': ApplyCompressor(); break;
case '6': ApplyEqualizer(); break;
case '7': ClearEffects(); break;
case '8': return;
}
}
}
static void ApplyHallReverb()
{
var reverb = new Reverb(
roomSize: 0.8f, // Large hall
damping: 0.2f, // Minimal damping
wetLevel: 0.4f, // 40% reverb
dryLevel: 0.7f // 70% original
);
sourceManager.CustomSampleProcessor = reverb;
Console.WriteLine("✅ Hall reverb applied");
}
static void ApplyRoomReverb()
{
var reverb = new Reverb(
roomSize: 0.4f, // Small room
damping: 0.6f, // More damping
wetLevel: 0.3f, // 30% reverb
dryLevel: 0.8f // 80% original
);
sourceManager.CustomSampleProcessor = reverb;
Console.WriteLine("✅ Room reverb applied");
}
static void ApplyEchoDelay()
{
var delay = new Delay(
delayMs: 500, // 500ms delay
feedback: 0.4f, // 40% feedback
wetLevel: 0.3f, // 30% effect
sampleRate: 44100
);
sourceManager.CustomSampleProcessor = delay;
Console.WriteLine("✅ Echo delay applied");
}
static void ApplyPingPongDelay()
{
var delay = new Delay(
delayMs: 250, // 250ms delay
feedback: 0.6f, // 60% feedback
wetLevel: 0.4f, // 40% effect
sampleRate: 44100
);
sourceManager.CustomSampleProcessor = delay;
Console.WriteLine("✅ Ping-pong delay applied");
}
static void ApplyCompressor()
{
var compressor = new Compressor(
threshold: 0.6f, // Compress above 60%
ratio: 4.0f, // 4:1 ratio
attackMs: 10f, // Fast attack
releaseMs: 100f, // Medium release
makeupGain: 1.2f, // Compensate gain
sampleRate: 44100f
);
sourceManager.CustomSampleProcessor = compressor;
Console.WriteLine("✅ Compressor applied (4:1 ratio)");
}
static void ApplyEqualizer()
{
var equalizer = new Equalizer(44100);
// Boost bass
equalizer.SetBandGain(0, 60f, 3.0f, 1.0f); // 60Hz +3dB
equalizer.SetBandGain(1, 100f, 2.5f, 1.0f); // 100Hz +2.5dB
// Slight mid cut
equalizer.SetBandGain(10, 800f, -1.0f, 2.0f); // 800Hz -1dB
// Presence boost
equalizer.SetBandGain(15, 3000f, 2.0f, 1.5f); // 3kHz +2dB
sourceManager.CustomSampleProcessor = equalizer;
Console.WriteLine("✅ EQ applied (Bass boost, presence enhancement)");
}
static void ClearEffects()
{
sourceManager.CustomSampleProcessor = null;
Console.WriteLine("✅ All effects cleared");
}
}
Real-Time Sine Wave Generator
Generate and stream audio in real-time with interactive control.
using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading;
using System.Threading.Tasks;
class SineGenerator
{
private static SourceSound realtimeSource;
private static bool isGenerating = false;
private static float frequency = 440f; // A4
private static float amplitude = 0.3f;
private static int sampleRate = 44100;
static async Task Main(string[] args)
{
try
{
OwnAudio.Initialize();
var sourceManager = SourceManager.Instance;
// Create real-time source
realtimeSource = sourceManager.AddRealTimeSource(1.0f, 2, "SineWave");
Console.WriteLine("🎵 Real-Time Sine Wave Generator");
Console.WriteLine($"Initial frequency: {frequency}Hz");
// Start audio generation
StartGeneration();
sourceManager.Play();
await RunGeneratorControl();
}
finally
{
StopGeneration();
OwnAudio.Free();
}
}
static void StartGeneration()
{
isGenerating = true;
Task.Run(async () =>
{
double phase = 0;
int bufferSize = 1024;
while (isGenerating && realtimeSource.State != SourceState.Idle)
{
float[] buffer = GenerateSineWave(bufferSize, ref phase);
realtimeSource.SubmitSamples(buffer);
// Control timing for smooth playback
await Task.Delay(10);
}
});
}
static float[] GenerateSineWave(int samples, ref double phase)
{
float[] buffer = new float[samples * 2]; // Stereo
double phaseIncrement = 2.0 * Math.PI * frequency / sampleRate;
for (int i = 0; i < samples; i++)
{
float sample = (float)(Math.Sin(phase) * amplitude);
buffer[i * 2] = sample; // Left channel
buffer[i * 2 + 1] = sample; // Right channel
phase += phaseIncrement;
if (phase >= 2.0 * Math.PI)
phase -= 2.0 * Math.PI;
}
return buffer;
}
static async Task RunGeneratorControl()
{
while (isGenerating)
{
Console.WriteLine("\n=== Sine Wave Controls ===");
Console.WriteLine($"Frequency: {frequency:F1}Hz | Amplitude: {amplitude:F2}");
Console.WriteLine("W/S: Frequency ±50Hz | A/D: Frequency ±10Hz");
Console.WriteLine("Q/E: Volume ±0.1 | Space: Musical notes | X: Exit");
var key = Console.ReadKey(true).Key;
switch (key)
{
case ConsoleKey.W: frequency += 50f; break;
case ConsoleKey.S: frequency -= 50f; break;
case ConsoleKey.A: frequency -= 10f; break;
case ConsoleKey.D: frequency += 10f; break;
case ConsoleKey.Q: amplitude = Math.Max(0.0f, amplitude - 0.1f); break;
case ConsoleKey.E: amplitude = Math.Min(1.0f, amplitude + 0.1f); break;
case ConsoleKey.Spacebar: await PlayMusicalNotes(); break;
case ConsoleKey.X: return;
}
// Clamp frequency to reasonable range
frequency = Math.Clamp(frequency, 20f, 20000f);
Console.WriteLine($"Updated - Freq: {frequency:F1}Hz, Vol: {amplitude:F2}");
}
}
static async Task PlayMusicalNotes()
{
float[] notes = { 261.63f, 293.66f, 329.63f, 349.23f, 392.00f, 440.00f, 493.88f, 523.25f }; // C-C octave
string[] noteNames = { "C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5" };
Console.WriteLine("\n🎼 Playing musical scale...");
for (int i = 0; i < notes.Length; i++)
{
frequency = notes[i];
Console.WriteLine($"♪ {noteNames[i]} ({frequency:F1}Hz)");
await Task.Delay(500);
}
frequency = 440f; // Reset to A4
Console.WriteLine("Scale complete!");
}
static void StopGeneration()
{
isGenerating = false;
}
}
Music Analysis and Chord Detection
Analyze audio files for musical content including chords, key, and tempo.
using Ownaudio;
using Ownaudio.Sources;
using Ownaudio.Utilities.Extensions;
using System;
using System.Threading.Tasks;
class MusicAnalyzer
{
static async Task Main(string[] args)
{
try
{
OwnAudio.Initialize();
var sourceManager = SourceManager.Instance;
// Get audio file from user
Console.WriteLine("🎼 Music Analyzer");
Console.Write("Enter path to audio file: ");
string filePath = Console.ReadLine();
if (string.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath))
{
Console.WriteLine("File not found. Using default: demo.mp3");
filePath = "demo.mp3";
}
// Load audio file
Console.WriteLine("Loading audio file...");
await sourceManager.AddOutputSource(filePath, "AnalysisTrack");
var track = sourceManager["AnalysisTrack"];
Console.WriteLine($"✅ Loaded: {System.IO.Path.GetFileName(filePath)}");
Console.WriteLine($"Duration: {track.Duration}");
// Start analysis
await PerformMusicAnalysis(sourceManager, "AnalysisTrack");
// Optional playback with visualization
await PlaybackWithAnalysis(sourceManager);
}
catch (Exception ex)
{
Console.WriteLine($"Analysis error: {ex.Message}");
}
finally
{
OwnAudio.Free();
}
}
static async Task PerformMusicAnalysis(SourceManager manager, string trackName)
{
Console.WriteLine("\n🔍 Analyzing musical content...");
Console.WriteLine("This may take a moment for longer tracks...");
try
{
// Perform chord detection analysis
var (timedChords, detectedKey, tempo) = manager.DetectChords(trackName, intervalSecond: 1.0f);
// Display analysis results
Console.WriteLine("\n📊 Analysis Results:");
Console.WriteLine($"🎵 Detected Key: {detectedKey ?? "Unknown"}");
Console.WriteLine($"🥁 Estimated Tempo: {tempo:F1} BPM");
Console.WriteLine($"🎼 Total Chord Changes: {timedChords.Count}");
// Display chord progression
Console.WriteLine("\n🎹 Chord Progression:");
Console.WriteLine("Time | Chord | Confidence");
Console.WriteLine("-----------|------------|------------");
foreach (var chord in timedChords)
{
string timeRange = $"{chord.StartTime:F1}s-{chord.EndTime:F1}s";
string confidenceStr = GetConfidenceString(chord.Confidence);
Console.WriteLine($"{timeRange,-10} | {chord.ChordName,-10} | {confidenceStr}");
}
// Musical analysis summary
AnalyzeChordProgression(timedChords, detectedKey);
}
catch (Exception ex)
{
Console.WriteLine($"Chord detection failed: {ex.Message}");
}
}
static string GetConfidenceString(float confidence)
{
return confidence switch
{
>= 0.9f => "🟢 Excellent",
>= 0.7f => "🟡 Good",
>= 0.5f => "🟠 Fair",
_ => "🔴 Poor"
};
}
static void AnalyzeChordProgression(System.Collections.Generic.List chords, string key)
{
if (chords.Count == 0) return;
Console.WriteLine("\n📈 Musical Analysis:");
// Find most common chords
var chordCounts = new System.Collections.Generic.Dictionary();
foreach (var chord in chords)
{
if (chord.ChordName != "Unknown")
{
chordCounts[chord.ChordName] = chordCounts.GetValueOrDefault(chord.ChordName, 0) + 1;
}
}
if (chordCounts.Count > 0)
{
Console.WriteLine("🏆 Most Common Chords:");
var sortedChords = chordCounts.OrderByDescending(x => x.Value).Take(5);
foreach (var (chord, count) in sortedChords)
{
double percentage = (count * 100.0) / chords.Count;
Console.WriteLine($" {chord}: {count} times ({percentage:F1}%)");
}
}
// Calculate average confidence
var validChords = chords.Where(c => c.ChordName != "Unknown").ToList();
if (validChords.Count > 0)
{
double avgConfidence = validChords.Average(c => c.Confidence);
Console.WriteLine($"🎯 Average Detection Confidence: {avgConfidence:F2} ({GetConfidenceString((float)avgConfidence)})");
}
// Detect key changes
if (!string.IsNullOrEmpty(key))
{
Console.WriteLine($"🗝️ Primary Key: {key}");
// Simple modulation detection (basic implementation)
var keyChanges = DetectSimpleKeyChanges(chords);
if (keyChanges.Count > 1)
{
Console.WriteLine("🔄 Possible Key Changes Detected:");
foreach (var change in keyChanges)
{
Console.WriteLine($" {change.Time:F1}s: Modulation to {change.NewKey}");
}
}
}
}
static System.Collections.Generic.List<(double Time, string NewKey)> DetectSimpleKeyChanges(
System.Collections.Generic.List chords)
{
var changes = new System.Collections.Generic.List<(double, string)>();
// This is a simplified key change detection
// In a real application, you'd use more sophisticated harmonic analysis
string previousKey = null;
foreach (var chord in chords.Where(c => c.ChordName != "Unknown"))
{
string currentKey = EstimateKeyFromChord(chord.ChordName);
if (currentKey != null && currentKey != previousKey && previousKey != null)
{
changes.Add((chord.StartTime, currentKey));
}
previousKey = currentKey;
}
return changes;
}
static string EstimateKeyFromChord(string chordName)
{
// Simplified key estimation based on chord root
// This is a basic implementation for demonstration
if (chordName.StartsWith("C")) return "C Major";
if (chordName.StartsWith("G")) return "G Major";
if (chordName.StartsWith("Am")) return "A Minor";
if (chordName.StartsWith("F")) return "F Major";
if (chordName.StartsWith("Dm")) return "D Minor";
return null; // Unknown key
}
static async Task PlaybackWithAnalysis(SourceManager manager)
{
Console.WriteLine("\n🎵 Playback with Real-time Analysis");
Console.WriteLine("Press P to play/pause, S to stop, Q to quit");
bool isPlaying = false;
var analysisTask = Task.CompletedTask;
while (true)
{
var key = Console.ReadKey(true).Key;
switch (key)
{
case ConsoleKey.P:
if (isPlaying)
{
manager.Pause();
Console.WriteLine("⏸️ Paused");
}
else
{
manager.Play();
Console.WriteLine("▶️ Playing");
analysisTask = ShowRealtimePosition(manager);
}
isPlaying = !isPlaying;
break;
case ConsoleKey.S:
manager.Stop();
Console.WriteLine("⏹️ Stopped");
isPlaying = false;
break;
case ConsoleKey.Q:
if (isPlaying) manager.Stop();
return;
}
}
}
static async Task ShowRealtimePosition(SourceManager manager)
{
while (manager.IsPlaying)
{
var position = manager.Position;
var duration = manager.Duration;
double progress = position.TotalSeconds / duration.TotalSeconds * 100;
Console.Write($"\r🎵 {position:mm\\:ss} / {duration:mm\\:ss} ({progress:F1}%) ");
await Task.Delay(1000);
}
Console.WriteLine();
}
}
🎚️ Professional Audio Mastering
Use OwnAudioSharp's intelligent matching system to achieve professional sound quality.
using Ownaudio.Utilities.Matchering;
class AudioMastering
{
static void Main(string[] args)
{
var analyzer = new AudioAnalyzer();
// Professional matchering - one line of code!
analyzer.ProcessEQMatching(
"my_track.wav", // Your audio
"reference.wav", // Professional reference
"mastered.wav" // Studio-quality output
);
// Optimize for different playback systems
analyzer.ProcessWithPreset("mastered.wav", "streaming.wav",
PlaybackSystem.RadioBroadcast);
Console.WriteLine("✅ Professional mastering complete!");
}
}
Real-Time Synthesizer with Effects
Advanced example combining real-time synthesis with live effects processing.
using Ownaudio;
using Ownaudio.Sources;
using Ownaudio.Processors;
using System;
using System.Threading;
using System.Threading.Tasks;
class RealtimeSynth
{
private static SourceSound synthSource;
private static SourceManager sourceManager;
private static bool isRunning = false;
// Synthesis parameters
private static float[] frequencies = new float[4]; // 4-voice polyphony
private static float[] amplitudes = new float[4];
private static double[] phases = new double[4];
private static bool[] noteStates = new bool[4];
// Effect parameters
private static bool reverbEnabled = false;
private static bool delayEnabled = false;
private static float masterVolume = 0.5f;
static async Task Main(string[] args)
{
try
{
OwnAudio.Initialize();
sourceManager = SourceManager.Instance;
// Create real-time synthesis source
synthSource = sourceManager.AddRealTimeSource(1.0f, 2, "Synthesizer");
Console.WriteLine("🎹 Real-Time Synthesizer");
Console.WriteLine("Features: 4-voice polyphony, reverb, delay");
// Start synthesis engine
StartSynthEngine();
sourceManager.Play();
await RunSynthController();
}
finally
{
StopSynthEngine();
OwnAudio.Free();
}
}
static void StartSynthEngine()
{
isRunning = true;
Task.Run(async () =>
{
int bufferSize = 512;
int sampleRate = 44100;
while (isRunning && synthSource.State != SourceState.Idle)
{
float[] buffer = GeneratePolyphonic(bufferSize, sampleRate);
synthSource.SubmitSamples(buffer);
await Task.Delay(5); // ~100 updates per second
}
});
}
static float[] GeneratePolyphonic(int samples, int sampleRate)
{
float[] buffer = new float[samples * 2]; // Stereo
for (int i = 0; i < samples; i++)
{
float mixedSample = 0f;
// Generate and mix all active voices
for (int voice = 0; voice < 4; voice++)
{
if (noteStates[voice] && frequencies[voice] > 0)
{
double phaseIncrement = 2.0 * Math.PI * frequencies[voice] / sampleRate;
// Generate waveform (saw wave for richer harmonics)
float sample = GenerateSawWave(phases[voice]) * amplitudes[voice];
mixedSample += sample;
phases[voice] += phaseIncrement;
if (phases[voice] >= 2.0 * Math.PI)
phases[voice] -= 2.0 * Math.PI;
}
}
// Apply master volume
mixedSample *= masterVolume;
// Store stereo
buffer[i * 2] = mixedSample; // Left
buffer[i * 2 + 1] = mixedSample; // Right
}
return buffer;
}
static float GenerateSawWave(double phase)
{
// Sawtooth wave: ramp from -1 to 1
return (float)(2.0 * (phase / (2.0 * Math.PI)) - 1.0);
}
static async Task RunSynthController()
{
Console.WriteLine("\n🎛️ Synthesizer Controls:");
Console.WriteLine("Piano Keys: Q W E R (voices 1-4)");
Console.WriteLine("Octaves: Z X C V (low to high)");
Console.WriteLine("Effects: 1=Reverb 2=Delay 3=Clear");
Console.WriteLine("Volume: + - (master volume)");
Console.WriteLine("ESC: Exit");
// Musical note frequencies (4th octave)
var noteFrequencies = new System.Collections.Generic.Dictionary
{
{ ConsoleKey.Q, 261.63f }, // C4
{ ConsoleKey.W, 293.66f }, // D4
{ ConsoleKey.E, 329.63f }, // E4
{ ConsoleKey.R, 349.23f }, // F4
{ ConsoleKey.T, 392.00f }, // G4
{ ConsoleKey.Y, 440.00f }, // A4
{ ConsoleKey.U, 493.88f }, // B4
};
float octaveMultiplier = 1.0f;
while (isRunning)
{
var keyInfo = Console.ReadKey(true);
var key = keyInfo.Key;
switch (key)
{
case ConsoleKey.Escape:
return;
// Octave controls
case ConsoleKey.Z: octaveMultiplier = 0.5f; Console.WriteLine("🎵 Low octave"); break;
case ConsoleKey.X: octaveMultiplier = 1.0f; Console.WriteLine("🎵 Mid octave"); break;
case ConsoleKey.C: octaveMultiplier = 2.0f; Console.WriteLine("🎵 High octave"); break;
case ConsoleKey.V: octaveMultiplier = 4.0f; Console.WriteLine("🎵 Very high octave"); break;
// Effect controls
case ConsoleKey.D1: ToggleReverb(); break;
case ConsoleKey.D2: ToggleDelay(); break;
case ConsoleKey.D3: ClearEffects(); break;
// Volume controls
case ConsoleKey.OemPlus:
case ConsoleKey.Add:
masterVolume = Math.Min(1.0f, masterVolume + 0.1f);
Console.WriteLine($"🔊 Volume: {masterVolume:F1}");
break;
case ConsoleKey.OemMinus:
case ConsoleKey.Subtract:
masterVolume = Math.Max(0.0f, masterVolume - 0.1f);
Console.WriteLine($"🔉 Volume: {masterVolume:F1}");
break;
// Note triggers
default:
if (noteFrequencies.ContainsKey(key))
{
TriggerNote(noteFrequencies[key] * octaveMultiplier);
}
break;
}
}
}
static void TriggerNote(float frequency)
{
// Find an available voice
for (int i = 0; i < 4; i++)
{
if (!noteStates[i])
{
frequencies[i] = frequency;
amplitudes[i] = 0.3f; // Volume per voice
phases[i] = 0;
noteStates[i] = true;
Console.WriteLine($"🎹 Note ON: {frequency:F1}Hz (Voice {i + 1})");
// Auto-release after 1 second
Task.Delay(1000).ContinueWith(_ => ReleaseNote(i));
return;
}
}
Console.WriteLine("🚫 All voices busy!");
}
static void ReleaseNote(int voice)
{
if (voice >= 0 && voice < 4)
{
noteStates[voice] = false;
Console.WriteLine($"🎹 Note OFF: Voice {voice + 1}");
}
}
static void ToggleReverb()
{
reverbEnabled = !reverbEnabled;
if (reverbEnabled)
{
var reverb = new Reverb(0.6f, 0.4f, 0.4f, 0.7f);
sourceManager.CustomSampleProcessor = reverb;
Console.WriteLine("✅ Reverb ON");
}
else
{
sourceManager.CustomSampleProcessor = null;
Console.WriteLine("❌ Reverb OFF");
}
}
static void ToggleDelay()
{
delayEnabled = !delayEnabled;
if (delayEnabled)
{
var delay = new Delay(300, 0.4f, 0.3f, 44100);
sourceManager.CustomSampleProcessor = delay;
Console.WriteLine("✅ Delay ON");
}
else
{
sourceManager.CustomSampleProcessor = null;
Console.WriteLine("❌ Delay OFF");
}
}
static void ClearEffects()
{
sourceManager.CustomSampleProcessor = null;
reverbEnabled = false;
delayEnabled = false;
Console.WriteLine("🧹 All effects cleared");
}
static void StopSynthEngine()
{
isRunning = false;
// Release all notes
for (int i = 0; i < 4; i++)
{
noteStates[i] = false;
}
}
}
Audio Visualization with Avalonia
Create interactive waveform displays for audio applications.
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:audio="using:Ownaudio.Utilities"
x:Class="AudioVisualizer.MainWindow"
Title="Audio Visualizer" Height="600" Width="900">
<Grid RowDefinitions="Auto,*,Auto">
<!-- Controls -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10">
<Button Name="LoadButton" Content="Load Audio" Margin="5"/>
<Button Name="PlayButton" Content="Play" Margin="5"/>
<Button Name="PauseButton" Content="Pause" Margin="5"/>
<Button Name="StopButton" Content="Stop" Margin="5"/>
</StackPanel>
<!-- Waveform Display -->
<audio:WaveAvaloniaDisplay Grid.Row="1"
Name="WaveformDisplay"
WaveformBrush="DodgerBlue"
PlaybackPositionBrush="Red"
VerticalScale="1.5"
DisplayStyle="MinMax"
Margin="10"/>
<!-- Status Bar -->
<TextBlock Grid.Row="2" Name="StatusText"
Text="Ready" Margin="10"
HorizontalAlignment="Center"/>
</Grid>
</Window>
using Avalonia.Controls;
using Avalonia.Interactivity;
using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading.Tasks;
namespace AudioVisualizer
{
public partial class MainWindow : Window
{
private SourceManager sourceManager;
public MainWindow()
{
InitializeComponent();
InitializeAudio();
SetupEventHandlers();
}
private void InitializeAudio()
{
try
{
OwnAudio.Initialize();
sourceManager = SourceManager.Instance;
}
catch (Exception ex)
{
StatusText.Text = $"Audio initialization failed: {ex.Message}";
}
}
private void SetupEventHandlers()
{
LoadButton.Click += LoadButton_Click;
PlayButton.Click += PlayButton_Click;
PauseButton.Click += PauseButton_Click;
StopButton.Click += StopButton_Click;
// Handle waveform position changes
WaveformDisplay.PlaybackPositionChanged += OnPlaybackPositionChanged;
}
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
try
{
var dialog = new OpenFileDialog
{
Title = "Select Audio File",
Filters = new[]
{
new FileDialogFilter { Name = "Audio Files", Extensions = { "mp3", "wav", "flac", "ogg" } },
new FileDialogFilter { Name = "All Files", Extensions = { "*" } }
}
};
var files = await dialog.ShowAsync(this);
if (files?.Length > 0)
{
await LoadAudioFile(files[0]);
}
}
catch (Exception ex)
{
StatusText.Text = $"Load error: {ex.Message}";
}
}
private async Task LoadAudioFile(string filePath)
{
StatusText.Text = "Loading audio file...";
try
{
// Clear existing sources
sourceManager.Stop();
// Load new audio file
await sourceManager.AddOutputSource(filePath, "MainTrack");
// Load waveform data
var audioData = sourceManager["MainTrack"].GetFloatAudioData(TimeSpan.Zero);
WaveformDisplay.SetAudioData(audioData);
StatusText.Text = $"Loaded: {System.IO.Path.GetFileName(filePath)} ({sourceManager["MainTrack"].Duration})";
}
catch (Exception ex)
{
StatusText.Text = $"Failed to load: {ex.Message}";
}
}
private void PlayButton_Click(object sender, RoutedEventArgs e)
{
try
{
sourceManager.Play();
StatusText.Text = "Playing...";
// Start position updates
StartPositionUpdates();
}
catch (Exception ex)
{
StatusText.Text = $"Play error: {ex.Message}";
}
}
private void PauseButton_Click(object sender, RoutedEventArgs e)
{
sourceManager.Pause();
StatusText.Text = "Paused";
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
sourceManager.Stop();
WaveformDisplay.PlaybackPosition = 0;
StatusText.Text = "Stopped";
}
private void OnPlaybackPositionChanged(object sender, double position)
{
// User clicked/dragged on waveform - seek to position
if (sourceManager.Sources.Count > 0)
{
var newTime = TimeSpan.FromSeconds(position * sourceManager.Duration.TotalSeconds);
sourceManager.Seek(newTime);
}
}
private async void StartPositionUpdates()
{
while (sourceManager.IsPlaying)
{
// Update waveform playback position
if (sourceManager.Duration.TotalSeconds > 0)
{
double position = sourceManager.Position.TotalSeconds / sourceManager.Duration.TotalSeconds;
WaveformDisplay.PlaybackPosition = position;
}
await Task.Delay(50); // 20 FPS updates
}
}
protected override void OnClosed(EventArgs e)
{
sourceManager?.Stop();
OwnAudio.Free();
base.OnClosed(e);
}
}
}