Skip to main content

Chip

Struct Chip 

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

Opaque handle to a single emulated chip instance.

Implementations§

Source§

impl Chip

Source

pub fn chip_type(&self) -> ChipType

Which chip this instance represents.

Examples found in repository?
examples/vgmrender.rs (line 66)
65    fn chip_type(&self) -> ChipType {
66        self.chip.chip_type()
67    }
68
69    /// Queue a register write. `reg` encodes the register number in the low
70    /// byte and the port index in bits 8-9. Applied on the next call to
71    /// `generate`.
72    fn write(&mut self, reg: u32, data: u8) {
73        self.queue.push_back((reg, data));
74    }
75
76    fn write_data(&mut self, access: AccessClass, base: u32, data: &[u8]) {
77        let mut state = self.handler_state.borrow_mut();
78        for (index, value) in data.iter().copied().enumerate() {
79            write_byte(&mut state, access, base + index as u32, value);
80        }
81    }
82
83    fn seek_pcm(&mut self, pos: u32) {
84        *self.pcm_offset.borrow_mut() = pos;
85    }
86
87    fn read_pcm(&mut self) -> u8 {
88        let mut offset = self.pcm_offset.borrow_mut();
89        let state = self.handler_state.borrow();
90        let value = read_byte(&state, AccessClass::Pcm, *offset);
91        *offset = offset.saturating_add(1);
92        value
93    }
94
95    /// Advance emulation up to `output_start` and accumulate one stereo
96    /// sample into `buffer[0]` (left) / `buffer[1]` (right), matching
97    /// vgmrender.cpp's `vgm_chip::generate`.
98    fn generate(
99        &mut self,
100        output_start: EmulatedTime,
101        output_step: EmulatedTime,
102        buffer: &mut [i32],
103    ) {
104        let _ = output_step;
105
106        // dequeue at most one pending register write per output sample
107        if let Some((reg, data)) = self.queue.pop_front() {
108            let addr1 = 2 * ((reg >> 8) & 3);
109            let data1 = (reg & 0xff) as u8;
110            let addr2 = addr1
111                + if self.chip_type() == ChipType::Ym2149 {
112                    2
113                } else {
114                    1
115                };
116            self.chip.pin_mut().write(addr1, data1);
117            self.chip.pin_mut().write(addr2, data);
118        }
119
120        // generate at the chip's native rate, catching up to output_start
121        while self.pos <= output_start {
122            self.chip.pin_mut().generate(&mut self.native);
123            self.pos += self.step;
124        }
125
126        let channels = self.channels;
127        let out = &self.native;
128        match self.chip.chip_type() {
129            ChipType::Ym2203 => {
130                let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
131                buffer[0] += sum;
132                buffer[1] += sum;
133            }
134            ChipType::Ym2608 | ChipType::Ym2610 => {
135                buffer[0] += out[0] + out[2 % channels];
136                buffer[1] += out[1 % channels] + out[2 % channels];
137            }
138            ChipType::Ymf278B => {
139                buffer[0] += out[4 % channels];
140                buffer[1] += out[5 % channels];
141            }
142            _ if channels == 1 => {
143                buffer[0] += out[0];
144                buffer[1] += out[0];
145            }
146            _ => {
147                buffer[0] += out[0];
148                buffer[1] += out[1 % channels];
149            }
150        }
151    }
Source

pub fn channels(&self) -> u32

Number of output channels this chip produces per generated sample (via the concrete ymfm chip class’s OUTPUTS constant).

Examples found in repository?
examples/buildall.rs (line 15)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}
More examples
Hide additional examples
examples/vgmrender.rs (line 51)
39    fn new(chip_type: ChipType, clock: u32) -> Self {
40        let state = Rc::new(RefCell::new(VgmHandlerState {
41            data: std::array::from_fn(|_| Vec::new()),
42        }));
43        let pcm_offset = Rc::new(RefCell::new(0u32));
44        let chip = ffi::create_chip_with_callbacks(
45            chip_type,
46            clock,
47            Box::new(InterfaceCallbacks::new(vgm_handler_with_state(Rc::clone(
48                &state,
49            )))),
50        );
51        let channels = chip.channels() as usize;
52        let step: EmulatedTime = 0x1_0000_0000i64 / i64::from(chip.sample_rate());
53        Self {
54            chip,
55            channels,
56            queue: std::collections::VecDeque::new(),
57            pos: 0,
58            step,
59            native: vec![0i32; channels],
60            handler_state: state,
61            pcm_offset,
62        }
63    }
Source

pub fn sample_rate(&self) -> u32

Native output sample rate for the clock this chip was created with (via the ymfm sample_rate(uint32_t input_clock) API).

Examples found in repository?
examples/vgmrender.rs (line 52)
39    fn new(chip_type: ChipType, clock: u32) -> Self {
40        let state = Rc::new(RefCell::new(VgmHandlerState {
41            data: std::array::from_fn(|_| Vec::new()),
42        }));
43        let pcm_offset = Rc::new(RefCell::new(0u32));
44        let chip = ffi::create_chip_with_callbacks(
45            chip_type,
46            clock,
47            Box::new(InterfaceCallbacks::new(vgm_handler_with_state(Rc::clone(
48                &state,
49            )))),
50        );
51        let channels = chip.channels() as usize;
52        let step: EmulatedTime = 0x1_0000_0000i64 / i64::from(chip.sample_rate());
53        Self {
54            chip,
55            channels,
56            queue: std::collections::VecDeque::new(),
57            pos: 0,
58            step,
59            native: vec![0i32; channels],
60            handler_state: state,
61            pcm_offset,
62        }
63    }
Source

pub fn reset(self: Pin<&mut Self>)

Reset the chip to its post-power-on state (via the ymfm reset() API).

Examples found in repository?
examples/buildall.rs (line 6)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}
Source

pub fn set_fidelity(self: Pin<&mut Self>, fidelity: Fidelity)

Select the sample-rate/accuracy tradeoff (via the ymfm set_fidelity(opn_fidelity)). Only meaningful for YM2203/YM2608/YM2610/YM2610B; a no-op on other chips.

Source

pub fn set_instrument_data(self: Pin<&mut Self>, data: &[u8]) -> bool

Replace the 0x90-byte instrument data on OPLL-family chips. Returns false for unsupported chip types or an incorrectly sized data buffer.

Source

pub fn write(self: Pin<&mut Self>, offset: u32, data: u8)

Write to a register at offset, via the ymfm write(offset, data) (0/1 = address/data port, 2/3 = extended address/data port on chips that support it).

Examples found in repository?
examples/buildall.rs (line 13)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}
More examples
Hide additional examples
examples/vgmrender.rs (line 116)
98    fn generate(
99        &mut self,
100        output_start: EmulatedTime,
101        output_step: EmulatedTime,
102        buffer: &mut [i32],
103    ) {
104        let _ = output_step;
105
106        // dequeue at most one pending register write per output sample
107        if let Some((reg, data)) = self.queue.pop_front() {
108            let addr1 = 2 * ((reg >> 8) & 3);
109            let data1 = (reg & 0xff) as u8;
110            let addr2 = addr1
111                + if self.chip_type() == ChipType::Ym2149 {
112                    2
113                } else {
114                    1
115                };
116            self.chip.pin_mut().write(addr1, data1);
117            self.chip.pin_mut().write(addr2, data);
118        }
119
120        // generate at the chip's native rate, catching up to output_start
121        while self.pos <= output_start {
122            self.chip.pin_mut().generate(&mut self.native);
123            self.pos += self.step;
124        }
125
126        let channels = self.channels;
127        let out = &self.native;
128        match self.chip.chip_type() {
129            ChipType::Ym2203 => {
130                let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
131                buffer[0] += sum;
132                buffer[1] += sum;
133            }
134            ChipType::Ym2608 | ChipType::Ym2610 => {
135                buffer[0] += out[0] + out[2 % channels];
136                buffer[1] += out[1 % channels] + out[2 % channels];
137            }
138            ChipType::Ymf278B => {
139                buffer[0] += out[4 % channels];
140                buffer[1] += out[5 % channels];
141            }
142            _ if channels == 1 => {
143                buffer[0] += out[0];
144                buffer[1] += out[0];
145            }
146            _ => {
147                buffer[0] += out[0];
148                buffer[1] += out[1 % channels];
149            }
150        }
151    }
Source

pub fn read(self: Pin<&mut Self>, offset: u32) -> u8

Read from offset, via the ymfm read(offset) API.

Examples found in repository?
examples/buildall.rs (line 12)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}
Source

pub fn generate(self: Pin<&mut Self>, buffer: &mut [i32])

Generate buffer.len() / channels() samples at the chip’s native sample rate, overwriting buffer (channel-interleaved); wraps the ymfm generate(output_data*, numsamples) API. This generates one native sample at a time. For each sample, it also advances the internal clock counter used by timers, including those required by modes such as CSM, and by BUSY state tracking.

Examples found in repository?
examples/buildall.rs (line 17)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}
More examples
Hide additional examples
examples/vgmrender.rs (line 122)
98    fn generate(
99        &mut self,
100        output_start: EmulatedTime,
101        output_step: EmulatedTime,
102        buffer: &mut [i32],
103    ) {
104        let _ = output_step;
105
106        // dequeue at most one pending register write per output sample
107        if let Some((reg, data)) = self.queue.pop_front() {
108            let addr1 = 2 * ((reg >> 8) & 3);
109            let data1 = (reg & 0xff) as u8;
110            let addr2 = addr1
111                + if self.chip_type() == ChipType::Ym2149 {
112                    2
113                } else {
114                    1
115                };
116            self.chip.pin_mut().write(addr1, data1);
117            self.chip.pin_mut().write(addr2, data);
118        }
119
120        // generate at the chip's native rate, catching up to output_start
121        while self.pos <= output_start {
122            self.chip.pin_mut().generate(&mut self.native);
123            self.pos += self.step;
124        }
125
126        let channels = self.channels;
127        let out = &self.native;
128        match self.chip.chip_type() {
129            ChipType::Ym2203 => {
130                let sum = out[0] + out[1 % channels] + out[2 % channels] + out[3 % channels];
131                buffer[0] += sum;
132                buffer[1] += sum;
133            }
134            ChipType::Ym2608 | ChipType::Ym2610 => {
135                buffer[0] += out[0] + out[2 % channels];
136                buffer[1] += out[1 % channels] + out[2 % channels];
137            }
138            ChipType::Ymf278B => {
139                buffer[0] += out[4 % channels];
140                buffer[1] += out[5 % channels];
141            }
142            _ if channels == 1 => {
143                buffer[0] += out[0];
144                buffer[1] += out[0];
145            }
146            _ => {
147                buffer[0] += out[0];
148                buffer[1] += out[1 % channels];
149            }
150        }
151    }
Source

pub fn save_state(self: Pin<&mut Self>) -> Vec<u8>

Serialize the full internal chip state via the ymfm save_restore(ymfm_saved_state&) with saving = true).

Examples found in repository?
examples/buildall.rs (line 8)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}
Source

pub fn restore_state(self: Pin<&mut Self>, data: &[u8])

Restore state previously produced by save_state (via the ymfm save_restore(ymfm_saved_state&) with saving = false). The chip must be of the same type and clock as when the state was saved; ymfm does not version or validate the saved data itself.

Examples found in repository?
examples/buildall.rs (line 10)
3fn exercise_chip(chip_type: ChipType) {
4    let mut chip = ffi::create_chip(chip_type, 8_000_000);
5
6    chip.pin_mut().reset();
7
8    let saved = chip.pin_mut().save_state();
9    assert!(!saved.is_empty());
10    chip.pin_mut().restore_state(&saved);
11
12    chip.pin_mut().read(0);
13    chip.pin_mut().write(0, 0);
14
15    let channels = chip.channels() as usize;
16    let mut samples = vec![0_i32; channels * 20];
17    chip.pin_mut().generate(&mut samples);
18}

Trait Implementations§

Source§

impl ExternType for Chip

Source§

type Kind = Opaque

Source§

type Id

A type-level representation of the type’s C++ namespace and type name. Read more
Source§

impl UniquePtrTarget for Chip

Auto Trait Implementations§

§

impl !Freeze for Chip

§

impl !Send for Chip

§

impl !Sync for Chip

§

impl !Unpin for Chip

§

impl RefUnwindSafe for Chip

§

impl UnsafeUnpin for Chip

§

impl UnwindSafe for Chip

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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.