Skip to main content

DosAudio

Struct DosAudio 

Source
pub struct DosAudio { /* private fields */ }
Expand description

Game-thread hardware control, including port reads and device timers.

There is one owner of port I/O. Implementing IoDevice allows moving this object directly into a host bus. outb/inb do not charge time themselves; use advance, wait_us, or timestamps supplied by the host.

Fallible writes leave state unchanged when the queue is full. The infallible helpers and IoDevice::outb panic on overflow rather than lose commands.

Implementations§

Source§

impl DosAudio

Source

pub fn split(config: SoundConfig) -> Result<(Self, AudioEngine)>

Allocate the bounded command queue and construct both thread halves.

Source

pub fn now(&self) -> Tick

Current machine time, initially zero.

Source

pub fn speaker_tone(&self) -> Option<f64>

Frequency in hertz of the PIT tone that speaker port I/O currently plays.

None when the speaker is absent or port 61h has the PIT gate (bit 0) or speaker data (bit 1) clear, which includes bit-banged output. Melodies from AudioEngine::play_speaker run on the engine and are not reflected.

Source

pub fn pit(&self) -> Option<&Pit>

The machine’s 8253 timer, present with the PC speaker.

With the speaker installed this object owns ports 40h-43h: route them only here and read IRQ 0 timing from this timer instead of keeping a second one. None without a speaker; the host then owns its own Pit.

Source

pub fn advance(&mut self, duration: Tick)

Advance machine time without consuming wall time.

Source

pub fn advance_to(&mut self, at: Tick)

Advance to an absolute timestamp, servicing an attached PCM buffer. Panics on backwards time or command queue overflow.

Source

pub fn try_advance_to(&mut self, at: Tick) -> Result<()>

Advance and enqueue every due buffer DMA sample, or change nothing.

A full queue requires rendering queued audio, or advancing in smaller intervals. Infallible advance/advance_to and bus calls panic instead.

Source

pub fn wait_us(&mut self, micros: u64)

Busy-wait for an integer number of emulated microseconds.

Source

pub fn outb(&mut self, port: u16, value: u8)

Write at current machine time. Panics on command queue overflow.

Source

pub fn inb(&mut self, port: u16) -> u8

Read at current machine time. Unattached ports read FFh.

Source

pub fn try_outb_at(&mut self, at: Tick, port: u16, value: u8) -> Result<()>

Timestamped port write, with transactional queue overflow handling.

Source

pub fn play_pcm( &mut self, samples: impl Into<Arc<[u8]>>, sample_rate: u32, ) -> Result<SfxHandle>

Play one 1..=65,536-byte unsigned mono PCM buffer through the installed DSP.

Starting allocates and replaces the previous DSP transfer. Requested rates are 4,000..=23,000 Hz, rounded to the nearest integer-microsecond period; the returned handle reports the actual rate. Retain it while playing. Advance the control clock to supply bytes automatically. Buffer data and handles remain on the control side; the audio thread receives only DAC values.

Raw writes to the DSP reset/command ports cancel buffer ownership. FM and speaker I/O continue alongside PCM. Failed starts leave existing playback intact.

Source

pub fn attach_dma(&mut self, memory: Arc<ConventionalMemory>) -> Result<()>

Attach shared conventional memory and an internal 8237 controller. Call before attaching this object to a host bus: this expands its port map. Memory bytes are atomic; coordinate writes with advances for coherent samples.

Source

pub fn poll_dma_completion(&mut self) -> Option<DmaCompletion>

Pop one memory-DMA block completion. This does not acknowledge the ISA IRQ. Drain before retrying IrqQueueFull; refill memory before advancing past a block.

Source

pub fn next_dma_block_tick(&self) -> Option<Tick>

Next predicted DSP block boundary; masks/controller terminal count may stall it.

Source

pub fn next_dma_tick(&self) -> Option<Tick>

Earliest external DSP byte request, or None when stopped, paused, or buffer-owned.

Service each byte at this tick to preserve the DSP’s fractional clock phase. The timestamp can precede now() if the host has fallen behind. In that case service at now(); subsequent requests resume from there.

Source

pub fn try_dma_write_at( &mut self, at: Tick, channel: DmaChannel, value: u8, ) -> Result<()>

Supply one unsigned PCM byte from the host’s DMA controller.

The host owns masking, memory, page wrapping and terminal count. Call at next_dma_tick() after checking DRQ. Early, paused, unmatched and backwards transfers fail. Queue overflow leaves time, DSP state and IRQ unchanged, so the host should advance its DMA address only after this succeeds. Samples receive the same fixed output latency as port writes.

Source

pub fn try_dma_write16_at( &mut self, at: Tick, channel: DmaChannel, value: u16, ) -> Result<()>

Supply one SB16 word-wide DMA unit; bit interpretation follows the DSP mode. Queue overflow leaves the DSP, IRQ, and machine timestamp unchanged.

Source

pub fn try_inb_at(&mut self, at: Tick, port: u16) -> Result<u8>

Timestamped port read. Rejects backwards time without changing state.

Source

pub fn sound(&mut self, hz: f64) -> Result<()>

Play a square-wave PC speaker tone through the emulated ports.

Frequency must be finite and positive. The divisor is clamped to the PIT range, including zero as the encoding for 65,536.

Source

pub fn nosound(&mut self) -> Result<()>

Disconnect the PC speaker through port 61h.

Source

pub fn bus_device(self) -> impl IoDevice

Consume this control half as the object attached to a host’s bus.

Source

pub fn opl(&mut self) -> Result<Opl<'_>>

Borrow musical patch, note, and rhythm helpers for the installed OPL chips.

Source

pub fn start_capture(&mut self) -> Result<()>

Begin recording game-thread port writes. Returns an error if already active.

Source

pub fn finish_capture(&mut self) -> Option<Capture>

End the active capture, including idle time through the current timestamp.

Trait Implementations§

Source§

impl IoDevice for DosAudio

Source§

fn ports(&self) -> &[PortRange]

Ports decoded by this device. Keep this map stable while attached.
Source§

fn advance_to(&mut self, at: Tick)

Progress autonomous hardware activity up to at without accessing a port. Read more
Source§

fn outb(&mut self, at: Tick, port: u16, value: u8)

Write a byte after synchronizing hardware state to at.
Source§

fn inb(&mut self, at: Tick, port: u16) -> u8

Read a byte after synchronizing hardware state to at.
Source§

fn irq_request(&self, _at: Tick) -> Option<IrqRequest>

Current IRQ line and level, or None if the device has no IRQ output. Read more
Source§

fn dma_request(&self, _at: Tick) -> Option<DmaRequest>

Current asserted DRQ, or None when no DMA transfer is requested. Read more
Source§

fn irq_pending(&self, at: Tick) -> bool

Whether this device is asserting its IRQ output at at.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.