ym2149_core/chip.rs
1// Imports
2use crate::audio::{AudioChannel, AudioChannelData, Note};
3use crate::command::{Command, CommandOutput};
4use crate::envelopes::{Envelope, EnvelopeFrequency};
5use crate::errors::Error;
6use crate::io::{IoPort, IoPortMixerSettings};
7use crate::register::{LEVEL_REGS, Register, ValidRegister};
8
9// =========================================================
10// ====================== CHIP STRUCT ======================
11// =========================================================
12
13/// A YM2149 chip struct.
14///
15/// The master_clock_frequency value is used to convert a frequency into a tone period by .tone_hz()
16///
17/// Example code:
18/// ```no_run
19/// use ym2149_core::{
20/// command::{Command, CommandOutput},
21/// io::IoPortMixerSettings,
22/// chip::YM2149
23/// };
24///
25/// struct DebugWriter;
26///
27/// impl CommandOutput for DebugWriter {
28/// fn execute(&mut self, command: Command) {
29/// print!("Register 0b{:08b} ({:?}), ", command.register, command.register);
30/// println!("0b{:08b} ({:?})", command.value, command.value);
31/// }
32/// }
33///
34/// let mut chip = YM2149::new(
35/// DebugWriter{},
36/// 2_000_000,
37/// ).expect("Error building chip");
38///
39/// chip.setup_io_and_mixer(
40/// IoPortMixerSettings {
41/// tone_ch_a: true,
42/// ..Default::default()
43/// }
44/// );
45/// ```
46#[derive(Debug)]
47pub struct YM2149<C>
48where
49 C: CommandOutput,
50{
51 command_output: C,
52 master_clock_frequency: u32,
53 pub channel_data: [AudioChannelData; 3],
54 pub last_used_channel: Option<usize>,
55}
56
57impl<C> YM2149<C>
58where
59 C: CommandOutput,
60{
61 /// Create a new struct for the YM2149.
62 pub fn new(command_output: C, master_clock_frequency: u32) -> Result<Self, Error> {
63 match master_clock_frequency {
64 1_000_000..=4_000_000 => Ok(Self {
65 command_output,
66 master_clock_frequency,
67 channel_data: [
68 AudioChannelData::new(0),
69 AudioChannelData::new(1),
70 AudioChannelData::new(2)
71 ],
72 last_used_channel: None
73 }),
74 _ => Err(Error::InvalidClockFrequency(master_clock_frequency)) //"The master_clock_frequency must be between 1MHz-4MHz!")
75 }
76 }
77
78 /// Send a [Command](#Command).
79 pub fn command<R: ValidRegister + Copy>(&mut self, register: R, value: u8) {
80 self.command_output
81 .execute(Command::new(register.address(), value));
82 }
83
84 /// Setup the IO ports and the internal mixer according to the IoPortMixerSettings specified.
85 pub fn setup_io_and_mixer(&mut self, settings: IoPortMixerSettings) {
86 self.channel_data[0].enabled = settings.tone_ch_a;
87 self.channel_data[1].enabled = settings.tone_ch_b;
88 self.channel_data[2].enabled = settings.tone_ch_c;
89
90 self.command(Register::IoPortMixerSettings, settings.as_u8());
91 }
92
93 /// Write a value to one of the chip's [GPIO ports](#IoPort).
94 /// Note: This is a simple helper function, equivalent to ``self.command(port as u8, value);``
95 pub fn write_io(&mut self, port: IoPort, value: u8) {
96 self.command(port as u8, value);
97 }
98
99 /// Set the envelope generator's frequency.
100 pub fn set_envelope_frequency(&mut self, frequency: EnvelopeFrequency) -> Result<u16, Error> {
101 let r: u16 = frequency.as_ep(self.master_clock_frequency)?;
102
103 let rough: u8 = (r >> 8) as u8; // High byte
104 let fine: u8 = r as u8; // Low byte
105
106 self.command(Register::EFreq8bitRoughAdj, rough);
107 self.command(Register::EFreq8bitFineAdj, fine);
108
109 Ok(r)
110 }
111
112 /// Set the envelope generator's shape.
113 pub fn set_envelope_shape(&mut self, envelope: &Envelope) {
114 self.command(0xD, envelope.into());
115 }
116
117 /// Play a tone with a TP of `period` on an [AudioChannel](#AudioChannel).
118 ///
119 /// The formula for the frequency is
120 /// ``f = fMaster / (16 * TP)``, where:
121 /// - f: target frequency
122 /// - fMaster: master clock frequency
123 /// - TP: tone period
124 pub fn tone(&mut self, channel: AudioChannel, period: u16) -> Result<(), Error> {
125 if period > 2_u16.pow(12) {
126 return Err(Error::TonePeriodOutOfRange(period));
127 }
128
129 let bytes: [u8; 2] = period.to_le_bytes();
130 let register_pair_index = self.channel_data[channel.index()].address * 2;
131
132 self.command(register_pair_index, bytes[0]); // Fine adjustment, 8 bits
133 self.command(register_pair_index + 1, bytes[1]); // Rough adjustment, 4 bits
134 self.last_used_channel = Some(channel.index());
135
136 Ok(())
137 }
138
139 /// Play a tone of a given frequency in Hz on an [AudioChannel](#AudioChannel).
140 pub fn tone_hz(&mut self, channel: AudioChannel, frequency: u32) -> Result<(), Error> {
141 if frequency == 0 {
142 return Err(Error::DivisionByZero);
143 }
144
145 let tp: u32 = self.master_clock_frequency / (16 * frequency);
146 self.tone(channel, tp as u16)?; // Take lowest 16 bits
147
148 Ok(())
149 }
150
151 /// Play a [Note](#Note) on an [AudioChannel](#AudioChannel).
152 pub fn play_note(&mut self, channel: AudioChannel, note: &Note) -> Result<(), Error> {
153 self.channel_data[channel.index()].last_note = Some(note.clone());
154
155 self.tone_hz(
156 channel,
157 note.transpose(self.channel_data[channel.index()].pitch_bend).as_hz()
158 )?;
159
160 Ok(())
161 }
162
163 /// Set an AudioChannel's pitch bend (takes a MIDI command).
164 pub fn pitch_bend(&mut self, channel: AudioChannel, byte1: u8, byte2: u8, replay_last: bool) -> Result<f32, Error> {
165 self.channel_data[channel.index()].set_pitch_bend(byte1, byte2);
166 if replay_last {
167 self.replay_last_note(channel)?;
168 }
169
170 Ok(self.channel_data[channel.index()].pitch_bend)
171 }
172
173 /// Replay the last played note on a given channel.
174 pub fn replay_last_note(&mut self, channel: AudioChannel) -> Result<(), Error> {
175 let last_note = self.channel_data[channel.index()].last_note;
176
177 match last_note {
178 Some(last_note) => { self.play_note(channel, &last_note)?; Ok(()) },
179 None => Err(Error::NoLastNote)
180 }
181 }
182
183 /// Play a [Note](#Note) on an [AudioChannel](#AudioChannel) with a given [Envelope](#Envelope).
184 pub fn play_note_with_envelope(
185 &mut self,
186 channel: AudioChannel,
187 note: &Note,
188 with_envelope: &Envelope,
189 ) -> Result<(), Error> {
190 self.play_note(channel, note)?;
191 self.set_envelope_shape(with_envelope);
192 Ok(())
193 }
194
195 /// Set the frequency of the noise generator.
196 ///
197 /// Mask: 0x1F
198 pub fn set_noise_freq(&mut self, frequency: u8) -> Result<(), Error> {
199 if frequency <= 0x1F {
200 self.command(Register::NoiseFreq5bit, frequency);
201 Ok(())
202 } else {
203 Err(Error::NoiseFrequencyOutOfRange(frequency))
204 }
205 }
206
207 /// Set the volume of an [AudioChannel](#AudioChannel).
208 ///
209 /// **Note:** The channel level registers store 5 bits of data per channel.
210 ///
211 /// ---
212 ///
213 /// From the datasheet:
214 /// - Mode M selects whether the level is fixed (when M = 0) or variable (M = 1).
215 /// - When M = 0, the level is determined from one of 16 by level selection signals L3, L2, L1, and L0 which compromise the lower four bits.
216 /// - When M = 1, the level is determined by the 5 bit output of E4, E3, E2, E1, and E0 of the envelope generator of the SSG.
217 ///
218 /// | B7 (MSB) | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
219 /// |-----------|-----|-----|-----|-----|-----|-----|-----|
220 /// | N/A | N/A | N/A | M | L3 | L2 | L1 | L0 |
221 pub fn level(&mut self, channel: AudioChannel, level: u8) {
222 self.channel_data[channel.index()].level = level;
223 self.command(LEVEL_REGS[channel.index()] as u8, level & 0x1F);
224 }
225
226 // ============================================================
227 // ========================= THE VOID =========================
228 // ============================================================
229 // (All you'll find here is unimplemented / todo functionality)
230
231 #[allow(unused)]
232 /// Reads a value from a given register and outputs it to the data bus.
233 ///
234 /// ---
235 /// # Warning!
236 ///
237 /// Mode::READ makes the chip output 5V to the data bus. It is **STRONGLY** recommended
238 /// to use a level shifter in order to prevent permanent damage to your board.
239 ///
240 /// This method is **unimplemented** *(at least, not for now...)*
241 ///
242 /// Feel free to try implementing it yourself, at your own risk.
243 fn read(&self, register: Register) -> u8 {
244 unimplemented!("Mode::READ and any functions associated with it are not yet usable.");
245 }
246
247 #[allow(unused)]
248 /// Reads a value from a given I/O port and outputs it to the data bus.
249 ///
250 /// ---
251 /// # Warning!
252 ///
253 /// Mode::READ makes the chip output 5V to the data bus. It is **STRONGLY** recommended
254 /// to use a level shifter in order to prevent permanent damage to your board.
255 ///
256 /// This method is **unimplemented** *(at least, not for now...)*
257 ///
258 /// Feel free to try implementing it yourself, at your own risk.
259 fn read_io(&self, port: IoPort) -> u8 {
260 unimplemented!("Mode::READ and any functions associated with it are not yet usable.");
261 }
262}