mtrack 0.12.0

A multitrack audio and MIDI player for live performances.
Documentation
// Copyright (C) 2026 Michael Wilson <mike@mdwn.dev>
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
//
// Shared context for audio playback (song and sample sources). Carries
// format, buffer sizes, and shared pools so call sites don't thread many
// separate arguments.
//

use std::sync::Arc;

use crate::audio::format::TargetFormat;
use crate::audio::sample_source::BufferFillPool;
use crate::config::ResamplerType;

/// Context passed into playback and source-creation paths so they can
/// obtain target format, buffer size, and shared resources (e.g. buffer
/// fill pool) without many separate parameters.
#[derive(Clone)]
pub struct PlaybackContext {
    /// Target sample rate, format, and bit depth for output.
    pub target_format: TargetFormat,
    /// Device buffer size in frames (used for BufferedSampleSource capacity
    /// and for file decode buffer size).
    pub buffer_size: usize,
    /// Shared pool for prefilling BufferedSampleSource. If None, sources
    /// are not wrapped in BufferedSampleSource.
    pub buffer_fill_pool: Option<Arc<BufferFillPool>>,
    /// Which resampling algorithm to use when sample rates differ.
    pub resampler_type: ResamplerType,
}

impl PlaybackContext {
    /// Builds a context from the given format, buffer size, and optional pool.
    pub fn new(
        target_format: TargetFormat,
        buffer_size: usize,
        buffer_fill_pool: Option<Arc<BufferFillPool>>,
        resampler_type: ResamplerType,
    ) -> Self {
        Self {
            target_format,
            buffer_size,
            buffer_fill_pool,
            resampler_type,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new_without_pool() {
        let fmt = TargetFormat::default();
        let ctx = PlaybackContext::new(fmt.clone(), 1024, None, ResamplerType::Sinc);
        assert_eq!(ctx.target_format, fmt);
        assert_eq!(ctx.buffer_size, 1024);
        assert!(ctx.buffer_fill_pool.is_none());
    }

    #[test]
    fn new_with_pool() {
        let fmt = TargetFormat::default();
        let pool = Arc::new(BufferFillPool::new(1).unwrap());
        let ctx = PlaybackContext::new(fmt, 512, Some(pool.clone()), ResamplerType::Fft);
        assert!(ctx.buffer_fill_pool.is_some());
        assert_eq!(ctx.buffer_size, 512);
    }

    #[test]
    fn clone() {
        let fmt = TargetFormat::default();
        let ctx = PlaybackContext::new(fmt, 256, None, ResamplerType::Sinc);
        let ctx2 = ctx.clone();
        assert_eq!(ctx2.buffer_size, 256);
    }
}