Skip to content

Ownaudio is a cross-platform C# audio library using miniaudio and portaudio (playback, recording, real-time effects, chord detection, etc.)

License

Notifications You must be signed in to change notification settings

ModernMube/OwnAudioSharp

Repository files navigation

Logo
Buy Me a Coffee OwnAudioSharp Package OwnAudioSharp Package

OwnAudio is a platform-independent C# audio library that provides a high-level API for audio playback, recording, and processing. By default, it uses Miniaudio for audio I/O. If FFmpeg or PortAudio is installed, it automatically uses Portaudio and FFmpeg. This way, it can work with MiniAudio without any external dependencies. The implementation of MiniAudio also allowed the API to be used on mobile platforms. It is possible to manipulate audio data in real time (pitch change, tempo change, and various real-time effects). The API is able to detect musical chords from audio and create a timed list of chords. A feature has been built in to help game developers manage sound effects.

Features

  • Cross-platform compatibility (Windows, macOS, Linux, Android, iOS)
  • Audio playbook with support for various formats via FFmpeg, or MiniAudio (mp3, wav, flac) formats
  • Audio recording capabilities through input devices
  • Time stretching and pitch shifting using SoundTouch
  • Mixing multiple audio sources
  • Volume control and custom audio processing
  • Seeking within audio files
  • Real-time audio processing with custom sample processors
  • Audio data visualize customizable waveform display

🎵 NEW: Audio Matchering in OwnAudioSharp!

Professional mastering automatically - single line of code!

analyzer.ProcessEQMatching("source.wav", "reference.wav", "mastered.wav");

What you get:

  • Intelligent 10-band EQ matching
  • Multiband compression across 4 frequency bands
  • Psychoacoustic weighting and spectral masking
  • Distortion-protected automatic processing

🎯 Result: Your source audio will sound exactly like the reference track - professional mastering studio quality.

📖 Documentation and examples

The table below summarizes the supported operating systems, the APIs used, and their testing status.

System APIs Status
Windows PortAudio 2, MiniAudio, FFmpeg 6 Tested
Linux PortAudio 2, MiniAudio, FFmpeg 6 Tested
macOS PortAudio 2, MiniAudio, FFmpeg 6 Tested
Android MiniAudio This project is tested with BrowserStack
iOS MiniAudio This project is tested with BrowserStack

The library will attempt to find these dependencies in standard system locations but also supports specifying custom paths.

Installation

You can add this library to your project via NuGet (when published) or by directly referencing the project.

Required Libraries

You will find the required files in the LIBS folder in a compressed file. Extract the package appropriate for your operating system into the folder containing the compressed file. Depending on your operating system, you will need the following:

Windows

  • FFmpeg libraries (avcodec, avformat, avutil, etc.)
  • portaudio.dll

macOS

  • FFmpeg libraries (libavcodec.dylib, libavformat.dylib, libavutil.dylib, etc.)
  • libportaudio.dylib

Linux

  • FFmpeg libraries (libavcodec.so, libavformat.so, libavutil.so, etc.)
  • libportaudio.so.2

Support My Work

If you find this project helpful, consider buying me a coffee!

Buy Me A Coffee

Basic Usage

Here's a quick example of how to use OwnAudio to play an audio file:

using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading.Tasks;

try 
{
    // Initialize OwnAudio
    OwnAudio.Initialize();

    // Create a source manager
    var sourceManager = SourceManager.Instance;

    // Add an audio file
    await sourceManager.AddOutputSource("path/to/audio.mp3");

    // Play the audio
    sourceManager.Play();

    // Wait for the audio to finish
    Console.WriteLine("Press any key to stop playback...");
    Console.ReadKey();

    // Stop playback and clean up
    sourceManager.Stop();
}
catch (Exception ex)
{
    Console.WriteLine($"Audio error: {ex.Message}");
}
finally
{
    OwnAudio.Free();
}

Advanced Features

Mixing Multiple Audio Sources

using Ownaudio;
using Ownaudio.Sources;

// Add multiple audio files
await sourceManager.AddOutputSource("path/to/audio1.mp3", "Track1Name");
await sourceManager.AddOutputSource("path/to/audio2.mp3", "Track2Name");

// Adjust volume for individual sources
sourceManager["Track1Name"].Volume = 0.8f;  // 80% volume for first source
sourceManager["Track2Name"].Volume = 0.6f;  // 60% volume for second source

// Play mixed audio
sourceManager.Play();

Audio Recording

// Add an input source
await sourceManager.AddInputSource();

// Start recording to file
sourceManager.Play("output.wav", 16);  // 16-bit recording

Time Stretching and Pitch Shifting

// Change tempo without affecting pitch (value range -20 to +20)
sourceManager["Track1Name"].Tempo = 10.0;  // Speed up by 10%

// Change pitch without affecting tempo (value range -6 to +6 semitones)
sourceManager["Track1Name"].Pitch = 2.0;  // Raise pitch by 2 semitones

Seeking Within Audio

// Seek to a specific position
sourceManager.Seek(TimeSpan.FromSeconds(30));  // Seek to 30 seconds

Audio Processing

  • Reverb: Professional quality reverb based on Freeverb algorithm
  • Delay: Echo effect with feedback control
  • Distortion: Overdrive and soft clipping
  • Compressor: Dynamic range compression
  • Equalizer: 10-band parametric EQ
  • Chorus: Multi-voice modulation effect
  • Flanger: Variable delay modulation
  • Phaser: All-pass filter stages for phasing effect
  • Rotary: Rotary speaker simulation
  • DynamicAmp: Adaptive volume control
  • Enhancer: Harmonic enhancement
  • Overdrive: effect with tube-like saturation
  • Limiter: with look-ahead and smooth gain reduction

Custom Audio Processing

You can implement custom audio processing by implementing the SampleProcessorBase class:

using Ownaudio.Processors;

public class MyAudioProcessor : SampleProcessorBase
{
    public override void Process(Span<float> samples)
    {
        // Process audio samples
        for (int i = 0; i < samples.Length; i++)
        {
            // Example: Simple gain adjustment
            samples[i] *= 0.5f;  // 50% volume
        }
    }
    
    public override void Reset()
    {
        // Reset internal state if needed
    }
    
    public override void Reset()
    {
        // Reset internal state if needed
    }
}

// Apply the processor to source manager
var processor = new MyAudioProcessor();
sourceManager.CustomSampleProcessor = processor;

Audio Data Read

using System.Threading.Tasks;

// Add a real-time source
var realtimeSource = sourceManager.AddRealTimeSource(1.0f, 2); // Volume 1.0, stereo

// Submit audio samples in real-time
float[] samples = new float[1024]; // Your generated audio data
realtimeSource.SubmitSamples(samples);

Live Audio Streaming and Real-time Playback

The SourceSound class enables real-time audio streaming, perfect for:

  • Live audio synthesis
  • Network audio streaming
  • Real-time audio effects processing
  • Dynamic audio generation
using Ownaudio;
using Ownaudio.Sources;
using System;
using System.Threading.Tasks;

// Create a real-time audio source
var liveSource = sourceManager.AddRealTimeSource(1.0f, 2); // Volume, channels

// Example: Generate and stream sine wave in real-time
await Task.Run(async () =>
{
    int sampleRate = 44100;
    int frequency = 440; // A4 note
    float amplitude = 0.3f;
    int samplesPerBuffer = 1024;
    
    double phase = 0;
    double phaseIncrement = 2.0 * Math.PI * frequency / sampleRate;
    
    while (liveSource.State != SourceState.Idle)
    {
        float[] buffer = new float[samplesPerBuffer * 2]; // Stereo
        
        for (int i = 0; i < samplesPerBuffer; 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;
        }
        
        // Submit samples for real-time playback
        liveSource.SubmitSamples(buffer);
        
        // Control timing for smooth playback
        await Task.Delay(10);
    }
});

// Start playback
sourceManager.Play();

Network Audio Streaming Example

// Example: Receive audio data from network and play in real-time
var networkSource = sourceManager.AddRealTimeSource(1.0f, 2);

// Network audio receiver (pseudo-code)
networkClient.OnAudioDataReceived += (audioData) =>
{
    // Convert received network data to float array
    float[] samples = ConvertBytesToFloats(audioData);
    
    // Submit to real-time source for immediate playback
    networkSource.SubmitSamples(samples);
};

sourceManager.Play();

Custom Audio Generator

using System;
using System.Threading.Tasks;

public class AudioGenerator
{
    private SourceSound _source;
    private int _sampleRate;
    private bool _isGenerating;
    
    public AudioGenerator(SourceManager manager, int sampleRate = 44100)
    {
        _sampleRate = sampleRate;
        _source = manager.AddRealTimeSource(1.0f, 2);
    }
    
    public void StartGeneration()
    {
        _isGenerating = true;
        
        Task.Run(async () =>
        {
            while (_isGenerating)
            {
                float[] audioBuffer = GenerateAudio(1024);
                _source.SubmitSamples(audioBuffer);
                await Task.Delay(5); // Smooth streaming
            }
        });
    }
    
    public void StopGeneration()
    {
        _isGenerating = false;
    }
    
    private float[] GenerateAudio(int samples)
    {
        // Your custom audio generation logic here
        float[] buffer = new float[samples * 2]; // Stereo
        
        // Fill buffer with generated audio data
        for (int i = 0; i < samples; i++)
        {
            float sample = GenerateSample(); // Your generation method
            buffer[i * 2] = sample;     // Left
            buffer[i * 2 + 1] = sample; // Right
        }
        
        return buffer;
    }
    
    private float GenerateSample()
    {
        // Implement your audio generation algorithm
        return 0.0f;
    }
}

// Usage
var generator = new AudioGenerator(sourceManager);
generator.StartGeneration();
sourceManager.Play();

Audio Data Extraction

// Load source audio data into a byte array
byte[] audioByte = sourceManager.Sources[0].GetByteAudioData(TimeSpan.Zero);

// Load source audio data into a float array
float[] audioFloat = sourceManager.Sources[0].GetFloatAudioData(TimeSpan.Zero);

Chord Detection

Real-time or offline chord detection from musical notes.

Core Components

Detectors

  • BaseChordDetector - Basic chord detection with major, minor, and 7th chords
  • ExtendedChordDetector - Adds suspended, diminished, augmented, and add9 chords
  • OptimizedChordDetector - Advanced detection with ambiguity handling and alternatives
  • RealTimeChordDetector - Continuous analysis with stability filtering

Analysis

  • SongChordAnalyzer - Full song analysis with timed chord progressions
  • ChordAnalysis - Detailed analysis results with confidence scores and explanations

Quick Start

using Ownaudio.Utilities.OwnChordDetect.Detectors;
using Ownaudio.Utilities.OwnChordDetect.Analysis;
using Ownaudio.Utilities.Extensions;

// Basic chord detection
var detector = new BaseChordDetector(confidenceThreshold: 0.7f);
var analysis = detector.AnalyzeChord(notes);
Console.WriteLine($"Detected: {analysis.ChordName} (confidence: {analysis.Confidence})");

// Extended chord detection with alternatives
var extendedDetector = new OptimizedChordDetector();
var (chord, confidence, isAmbiguous, alternatives) = extendedDetector.DetectChordAdvanced(notes);

// Real-time analysis
var realtimeDetector = new RealTimeChordDetector(bufferSize: 5);
var (stableChord, stability) = realtimeDetector.ProcessNotes(newNotes);

// Full song analysis
var songAnalyzer = new SongChordAnalyzer(windowSize: 1.0f, hopSize: 0.5f);
var timedChords = songAnalyzer.AnalyzeSong(allSongNotes);

// Complete example with SourceManager
var sourceManager = SourceManager.Instance;
await sourceManager.AddOutputSource("music.mp3", "MusicTrack");

// Detect chords from the loaded audio
var (timedChords, detectedKey, tempo) = sourceManager.DetectChords("MusicTrack", intervalSecond: 1.0f);

Console.WriteLine($"Detected Key: {detectedKey}");
Console.WriteLine($"Detected Tempo: {tempo} BPM");

foreach (var chord in timedChords)
{
    Console.WriteLine($"{chord.StartTime:F1}s-{chord.EndTime:F1}s: {chord.ChordName} ({chord.Confidence:F2})");
}

Input Format

The library expects Note objects with:

  • Pitch - MIDI pitch number
  • Amplitude - Note volume (0.0-1.0)
  • StartTime / EndTime - Timing in seconds

Key Features

  • Template Matching - Uses chromagram analysis and cosine similarity
  • Ambiguity Detection - Identifies uncertain chord matches
  • Temporal Stability - Real-time filtering for consistent results
  • Extensible Templates - Add custom chord definitions
  • Song-level Analysis - Extract complete chord progressions with timing

Confidence Thresholds

  • 0.9+ - Very confident detection
  • 0.7+ - Likely correct
  • 0.5+ - Possible but uncertain
  • Below 0.5 - Marked as "Unknown"

WaveAvaloniaDisplay - Audio Visualization

A flexible, resource-efficient audio waveform visualization component for Avalonia applications.

Key Features

  • Multiple display styles: MinMax (classic waveform), Positive (half-wave rectified), or RMS (energy representation)
  • Zoom in/out: Supports zooming for detailed audio inspection
  • Interactive playback position: Users can change the playback position by clicking or dragging
  • Customizable appearance: Colors and scaling are fully customizable
  • Optimized performance: Minimal resource usage even with large audio files
  • File loading: Direct loading from audio files with automatic format detection

Usage

The following example demonstrates how to use the WaveAvaloniaDisplay component in an Avalonia application:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:audio="using:Ownaudio.Utilities"
        x:Class="MyAudioApp.MainWindow"
        Title="Audio Visualizer" Height="450" Width="800">

    <Grid>
        <audio:WaveAvaloniaDisplay x:Name="waveformDisplay"
                                WaveformBrush="DodgerBlue"
                                PlaybackPositionBrush="Red"
                                VerticalScale="1.0"
                                DisplayStyle="MinMax"/>
    </Grid>
</Window>

C# Code

using Ownaudio.Utilities;
using System;
using System.IO;
using System.Threading.Tasks;

// Set audio data from existing float array
waveformDisplay.SetAudioData(sourceManager.Sources[0].GetFloatAudioData(TimeSpan.Zero));

// Handle playback position changes
waveformDisplay.PlaybackPositionChanged += OnPlaybackPositionChanged;

// Load directly from audio file
waveformDisplay.LoadFromAudioFile("audio.mp3");

// Load with specific decoder preference
waveformDisplay.LoadFromAudioFile("audio.mp3", preferFFmpeg: true);

// Asynchronous loading
await waveformDisplay.LoadFromAudioFileAsync("large_audio.wav");

// Loading from stream
using var fileStream = File.OpenRead("audio.mp3");
waveformDisplay.LoadFromAudioStream(fileStream);

private void OnPlaybackPositionChanged(object sender, double position)
{
    // Update the actual audio playback position
    sourceManager.Seek(TimeSpan.FromSeconds(position * sourceManager.Duration.TotalSeconds));
}

Properties

Property Type Description
WaveformBrush IBrush The color of the waveform
PlaybackPositionBrush IBrush The color of the playback position indicator
VerticalScale double Vertical scaling of the waveform (1.0 = original size)
DisplayStyle WaveformDisplayStyle The waveform display style (MinMax, Positive, RMS)
ZoomFactor double Zoom factor (1.0 = full view, larger values = more detailed view)
ScrollOffset double Horizontal scroll position (0.0 - 1.0)
PlaybackPosition double Current playback position (0.0 - 1.0)

Events

Event Parameter Description
PlaybackPositionChanged double Triggered when the user changes the playback position

Architecture

The library follows a layered architecture:

  1. Native Libraries (FFmpeg & PortAudio/MiniAudio) - Low-level audio I/O and decoding
  2. Decoders - Audio file decoding (FFmpegDecoder, MiniDecoder)
  3. Sources - Audio source management (Source, SourceInput, SourceSound)
  4. SourceManager - Mixing and controlling multiple sources
  5. Processors - Custom audio processing pipeline
  6. Effects - Built-in audio effects library
  7. Engines - Audio engine abstraction (PortAudio/MiniAudio)

Engine Configuration

You can configure the audio engine with specific parameters:

using Ownaudio.Engines;

// Initialize first
OwnAudio.Initialize();

// Configure output engine options
SourceManager.OutputEngineOptions = new AudioEngineOutputOptions(
    OwnAudioEngine.EngineChannels.Stereo, 
    44100, 
    0.02 // Low latency
);

// Configure input engine options
SourceManager.InputEngineOptions = new AudioEngineInputOptions(
    OwnAudioEngine.EngineChannels.Mono, 
    44100, 
    0.02 // Low latency
);

// Set frames per buffer
SourceManager.EngineFramesPerBuffer = 512;

Matchering

The professional audio matchering function built into OwnAudioSharp automatically analyzes and adjusts the spectral and dynamic properties of source audio to match the characteristics of a target audio file. This technology enables achieving consistent sound across musical masters or reproducing the sound of reference tracks.

Features

  • Intelligent EQ matching: 10-band frequency spectrum analysis and automatic equalization
  • Multiband compression: 4-band dynamic processing with frequency-specific settings
  • Psychoacoustic weighting: A-weighting and equal loudness contour consideration
  • Dynamic amplification: Automatic loudness level adjustment
  • Distortion protection: Built-in headroom calculation and safe boost limiting
  • Spectral masking: Analysis and compensation of frequency masking effects

Usage

using Ownaudio.Utilities.Matchering;

// Audio matchering example
var analyzer = new AudioAnalyzer();

// Process source and target audio files
analyzer.ProcessEQMatching(
    sourceFile: "input_track.wav",     // Audio to be processed
    targetFile: "reference.wav",       // Reference audio
    outputFile: "mastered_track.wav"   // Output
);

// The processing automatically:
// 1. Analyzes spectral properties of both files
// 2. Calculates optimal EQ settings
// 3. Applies multiband compression
// 4. Performs dynamic amplification
// 5. Generates distortion-protected output

Detailed Analysis

// Individual audio spectrum analysis
var sourceSpectrum = analyzer.AnalyzeAudioFile("source.wav");

Console.WriteLine($"RMS level: {sourceSpectrum.RMSLevel:F3}");
Console.WriteLine($"Peak level: {sourceSpectrum.PeakLevel:F3}");
Console.WriteLine($"Dynamic range: {sourceSpectrum.DynamicRange:F1} dB");
Console.WriteLine($"Loudness: {sourceSpectrum.Loudness:F1} LUFS");

// Output frequency band energies
for (int i = 0; i < sourceSpectrum.FrequencyBands.Length; i++)
{
    Console.WriteLine($"Band {i}: {sourceSpectrum.FrequencyBands[i]:F3}");
}

Technical Specifications

Frequency Bands

  • 10 octave bands: 31.25 Hz - 16 kHz
  • FFT analysis: Optimized window size (4096-16384 samples)
  • Blackman-Harris window: Minimal spectral leakage
  • 87.5% overlap: High-precision frequency resolution

Compression Settings

  • 4 frequency bands: Low, low-mid, high-mid, high
  • Adaptive parameters: Band-specific threshold, ratio, attack/release times
  • Makeup gain: Automatic level compensation

Safety Features

  • Frequency-specific boost limits: 4-10 dB maximum depending on frequency
  • Dynamic headroom calculation: Crest factor and loudness-based protection
  • EQ curve smoothing: Natural-sounding transitions
  • Clipping protection: -0.1 dB ceiling limiter

Output Example

=== ANALYSIS RESULTS ===
Source - RMS: 0.123, Peak: 0.876, Loudness: -14.2 LUFS
Target - RMS: 0.187, Peak: 0.932, Loudness: -9.8 LUFS
Crest Factor - Source: 15.1dB, Target: 13.9dB
Distortion Risk: LOW (Total boost: 8.2dB)

EQ Adjustments (with distortion protection):
31Hz: +2.1 dB
63Hz: +3.4 dB
125Hz: +1.8 dB
250Hz: -0.5 dB
500Hz: +0.2 dB
1kHz: -1.2 dB
2kHz: +1.6 dB
4kHz: +0.8 dB
8kHz: -2.1 dB
16kHz: +1.9 dB

=== SAFETY FEATURES ACTIVE ===
✓ Frequency-specific boost limits
✓ Dynamic headroom calculation
✓ Psychoacoustic weighting
✓ EQ curve smoothing
✓ Safety limiter (-0.1dB ceiling)
✓ Real-time clipping detection

Application Areas

  • Mastering: Achieving consistent sound across albums
  • Remix/remaster: Bringing classic recordings to modern sound standards
  • Podcast/speech: Applying professional audio techniques
  • Game audio: Ensuring consistent audio atmosphere
  • Streaming: Meeting platform-specific loudness standards

Audio matchering automatically applies the most modern psychoacoustic algorithms and safe processing techniques to ensure professional-quality results for every use case.

Acknowledgements

Special thanks to the creators of the following repositories, whose code was instrumental in the development of OwnAudio:

  • Bufdio - Audio playback library for .NET
  • FFmpeg.AutoGen - FFmpeg auto generated unsafe bindings for C#/.NET
  • soundtouch.net - .NET wrapper for the SoundTouch audio processing library
  • Avalonia - Cross-platform .NET UI framework
  • SoundFlow - A powerful and extensible cross-platform .NET audio engine.

About

Ownaudio is a cross-platform C# audio library using miniaudio and portaudio (playback, recording, real-time effects, chord detection, etc.)

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages