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
impl DosAudio
Sourcepub fn split(config: SoundConfig) -> Result<(Self, AudioEngine)>
pub fn split(config: SoundConfig) -> Result<(Self, AudioEngine)>
Allocate the bounded command queue and construct both thread halves.
Sourcepub fn speaker_tone(&self) -> Option<f64>
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.
Sourcepub fn pit(&self) -> Option<&Pit>
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.
Sourcepub fn advance_to(&mut self, at: Tick)
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.
Sourcepub fn try_advance_to(&mut self, at: Tick) -> Result<()>
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.
Sourcepub fn wait_us(&mut self, micros: u64)
pub fn wait_us(&mut self, micros: u64)
Busy-wait for an integer number of emulated microseconds.
Sourcepub fn outb(&mut self, port: u16, value: u8)
pub fn outb(&mut self, port: u16, value: u8)
Write at current machine time. Panics on command queue overflow.
Sourcepub fn inb(&mut self, port: u16) -> u8
pub fn inb(&mut self, port: u16) -> u8
Read at current machine time. Unattached ports read FFh.
Sourcepub fn try_outb_at(&mut self, at: Tick, port: u16, value: u8) -> Result<()>
pub fn try_outb_at(&mut self, at: Tick, port: u16, value: u8) -> Result<()>
Timestamped port write, with transactional queue overflow handling.
Sourcepub fn play_pcm(
&mut self,
samples: impl Into<Arc<[u8]>>,
sample_rate: u32,
) -> Result<SfxHandle>
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.
Sourcepub fn attach_dma(&mut self, memory: Arc<ConventionalMemory>) -> Result<()>
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.
Sourcepub fn poll_dma_completion(&mut self) -> Option<DmaCompletion>
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.
Sourcepub fn next_dma_block_tick(&self) -> Option<Tick>
pub fn next_dma_block_tick(&self) -> Option<Tick>
Next predicted DSP block boundary; masks/controller terminal count may stall it.
Sourcepub fn next_dma_tick(&self) -> Option<Tick>
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.
Sourcepub fn try_dma_write_at(
&mut self,
at: Tick,
channel: DmaChannel,
value: u8,
) -> Result<()>
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.
Sourcepub fn try_dma_write16_at(
&mut self,
at: Tick,
channel: DmaChannel,
value: u16,
) -> Result<()>
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.
Sourcepub fn try_inb_at(&mut self, at: Tick, port: u16) -> Result<u8>
pub fn try_inb_at(&mut self, at: Tick, port: u16) -> Result<u8>
Timestamped port read. Rejects backwards time without changing state.
Sourcepub fn sound(&mut self, hz: f64) -> Result<()>
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.
Sourcepub fn bus_device(self) -> impl IoDevice
pub fn bus_device(self) -> impl IoDevice
Consume this control half as the object attached to a host’s bus.
Sourcepub fn opl(&mut self) -> Result<Opl<'_>>
pub fn opl(&mut self) -> Result<Opl<'_>>
Borrow musical patch, note, and rhythm helpers for the installed OPL chips.
Sourcepub fn start_capture(&mut self) -> Result<()>
pub fn start_capture(&mut self) -> Result<()>
Begin recording game-thread port writes. Returns an error if already active.
Sourcepub fn finish_capture(&mut self) -> Option<Capture>
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
impl IoDevice for DosAudio
Source§fn ports(&self) -> &[PortRange]
fn ports(&self) -> &[PortRange]
Source§fn advance_to(&mut self, at: Tick)
fn advance_to(&mut self, at: Tick)
at without accessing a port. Read moreSource§fn outb(&mut self, at: Tick, port: u16, value: u8)
fn outb(&mut self, at: Tick, port: u16, value: u8)
at.Source§fn inb(&mut self, at: Tick, port: u16) -> u8
fn inb(&mut self, at: Tick, port: u16) -> u8
at.Source§fn irq_request(&self, _at: Tick) -> Option<IrqRequest>
fn irq_request(&self, _at: Tick) -> Option<IrqRequest>
None if the device has no IRQ output. Read moreSource§fn dma_request(&self, _at: Tick) -> Option<DmaRequest>
fn dma_request(&self, _at: Tick) -> Option<DmaRequest>
None when no DMA transfer is requested. Read moreSource§fn irq_pending(&self, at: Tick) -> bool
fn irq_pending(&self, at: Tick) -> bool
at.