1use core::fmt::{self, Debug};
10use core::num::NonZeroU16;
11use core::marker::PhantomData;
12
13pub mod serial128;
14#[cfg(feature = "snapshot")] mod serde;
15#[cfg(feature = "snapshot")] use ::serde::Serialize;
16
17use spectrusty_core::{
18 audio::{Blep, AmpLevels},
19 bus::{
20 BusDevice, NullDevice,
21 OptionalBusDevice, DynamicBus, DynamicSerdeBus, NamedBusDevice
22 },
23 clock::FTs
24};
25
26pub use crate::ay::{
27 audio::Ay3_891xAudio,
28 Ay3_8910Io, Ay3_8912Io, Ay3_8913Io, AyIoPort, AyIoNullPort, AyRegister,
29 AyPortDecode, Ay128kPortDecode, AyFullerBoxPortDecode
30};
31
32pub trait PassByAyAudioBusDevice {}
35
36pub type Ay3_891xMelodik<D> = Ay3_891xBusDevice<Ay128kPortDecode,
38 AyIoNullPort<<D as BusDevice>::Timestamp>,
39 AyIoNullPort<<D as BusDevice>::Timestamp>,
40 D>;
41pub type Ay3_891xFullerBox<D> = Ay3_891xBusDevice<AyFullerBoxPortDecode,
43 AyIoNullPort<<D as BusDevice>::Timestamp>,
44 AyIoNullPort<<D as BusDevice>::Timestamp>,
45 D>;
46
47impl<D: BusDevice> fmt::Display for Ay3_891xMelodik<D> {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 f.write_str("AY-3-8913 (Melodik)")
50 }
51}
52
53impl<D: BusDevice> fmt::Display for Ay3_891xFullerBox<D> {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.write_str("AY-3-8913 (Fuller Box)")
56 }
57}
58pub trait AyAudioBusDevice: BusDevice {
68 fn render_ay_audio<L: AmpLevels<B::SampleDelta>, B: Blep>(
73 &mut self,
74 blep: &mut B,
75 end_ts: <Self as BusDevice>::Timestamp,
76 frame_tstates: FTs,
77 chans: [usize; 3]
78 );
79}
80
81#[derive(Clone, Default, Debug)]
87#[cfg_attr(feature = "snapshot", derive(Serialize))]
88#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
89pub struct Ay3_891xBusDevice<P, A, B, D: BusDevice> {
90 pub ay_sound: Ay3_891xAudio,
92 pub ay_io: Ay3_8910Io<D::Timestamp, A, B>,
94 bus: D,
95 #[cfg_attr(feature = "snapshot", serde(skip))]
96 _port_decode: PhantomData<P>
97}
98
99impl<D> PassByAyAudioBusDevice for Box<D> where D: PassByAyAudioBusDevice {}
100
101impl<D, N> AyAudioBusDevice for D
102 where D::Timestamp: Into<FTs>,
103 D: BusDevice<NextDevice=N> + PassByAyAudioBusDevice,
104 N: BusDevice<Timestamp=D::Timestamp> + AyAudioBusDevice
105{
106 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: D::Timestamp, frame_tstates: FTs, chans: [usize; 3])
107 where B: Blep,
108 L: AmpLevels<B::SampleDelta>
109 {
110 self.next_device_mut().render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
111 }
112}
113
114macro_rules! impl_ay_audio_boxed_bus_device {
115 ($device:ident<$($ty:ident),*>) => {
116 impl_ay_audio_boxed_bus_device!($device<$($ty),*> where );
117 };
118 ($device:ident<$($ty:ident),*> where $($cond:tt)*) => {
119 impl<$($ty),*> AyAudioBusDevice for Box<$device<$($ty),*>>
120 where $device<$($ty),*>: AyAudioBusDevice + BusDevice,
121 $($cond)*
122 {
123 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: <Self as BusDevice>::Timestamp, frame_tstates: FTs, chans: [usize; 3])
124 where B: Blep,
125 L: AmpLevels<B::SampleDelta>
126 {
127 (**self).render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
128 }
129 }
130 };
131}
132
133impl_ay_audio_boxed_bus_device!(OptionalBusDevice<D, N>);
134impl<D, N> AyAudioBusDevice for OptionalBusDevice<D, N>
135 where <D as BusDevice>::Timestamp: Into<FTs> + Copy,
136 D: AyAudioBusDevice + BusDevice,
137 N: AyAudioBusDevice + BusDevice<Timestamp=D::Timestamp>
138{
139 #[inline(always)]
143 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: D::Timestamp, frame_tstates: FTs, chans: [usize; 3])
144 where B: Blep,
145 L: AmpLevels<B::SampleDelta>
146 {
147 if let Some(ref mut device) = self.device {
148 device.render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
149 }
150 self.next_device.render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
151 }
152}
153
154impl<T> AyAudioBusDevice for dyn NamedBusDevice<T>
155 where T: Into<FTs> + Copy + fmt::Debug + 'static
156{
157 #[inline]
163 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: T, frame_tstates: FTs, chans: [usize; 3])
164 where L: AmpLevels<B::SampleDelta>,
165 B: Blep
166 {
167 if let Some(ay_dev) = self.downcast_mut::<Ay3_891xMelodik<NullDevice<T>>>() {
168 ay_dev.render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
169 }
170 else if let Some(ay_dev) = self.downcast_mut::<Ay3_891xFullerBox<NullDevice<T>>>() {
171 ay_dev.render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
172 }
173 }
174}
175
176impl_ay_audio_boxed_bus_device!(DynamicBus<D> where D: BusDevice);
177impl<D> AyAudioBusDevice for DynamicBus<D>
178 where <D as BusDevice>::Timestamp: Into<FTs> + Copy + fmt::Debug + 'static,
179 D: AyAudioBusDevice + BusDevice
180{
181 #[inline]
185 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: D::Timestamp, frame_tstates: FTs, chans: [usize; 3])
186 where B: Blep,
187 L: AmpLevels<B::SampleDelta>
188 {
189 for dev in self.into_iter() {
190 dev.render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
191 }
192 self.next_device_mut().render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
193 }
194}
195
196impl_ay_audio_boxed_bus_device!(DynamicSerdeBus<SD, D> where D: BusDevice);
197impl<SD, D> AyAudioBusDevice for DynamicSerdeBus<SD, D>
198 where <D as BusDevice>::Timestamp: Into<FTs> + Copy + fmt::Debug + 'static,
199 D: AyAudioBusDevice + BusDevice
200{
201 #[inline]
205 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: D::Timestamp, frame_tstates: FTs, chans: [usize; 3])
206 where B: Blep,
207 L: AmpLevels<B::SampleDelta>
208 {
209 (**self).render_ay_audio::<L, B>(blep, end_ts, frame_tstates, chans)
210 }
211}
212
213impl_ay_audio_boxed_bus_device!(Ay3_891xBusDevice<P, PA, PB, D> where D: BusDevice);
214impl<P, PA, PB, D> AyAudioBusDevice for Ay3_891xBusDevice<P, PA, PB, D>
215 where Self: BusDevice<Timestamp=D::Timestamp>,
216 D: BusDevice,
217 D::Timestamp: Into<FTs>
218{
219 #[inline(always)]
220 fn render_ay_audio<L, B>(&mut self, blep: &mut B, end_ts: D::Timestamp, frame_tstates: FTs, chans: [usize; 3])
221 where B: Blep,
222 L: AmpLevels<B::SampleDelta>
223 {
224 let end_ts = end_ts.into();
225 let changes = self.ay_io.recorder.drain_ay_reg_changes();
226 self.ay_sound.render_audio::<L,_,_>(changes, blep, end_ts, frame_tstates, chans)
227 }
228}
229
230impl_ay_audio_boxed_bus_device!(NullDevice<T>);
231impl<T: Into<FTs> + fmt::Debug> AyAudioBusDevice for NullDevice<T> {
232 #[inline(always)]
233 fn render_ay_audio<L, B>(&mut self, _blep: &mut B, _end_ts: T, _frame_tstates: FTs, _chans: [usize; 3])
234 where L: AmpLevels<B::SampleDelta>,
235 B: Blep
236 {}
237}
238
239impl<P, A, B, D> BusDevice for Ay3_891xBusDevice<P, A, B, D>
240 where P: AyPortDecode,
241 A: AyIoPort<Timestamp=D::Timestamp> + Debug,
242 B: AyIoPort<Timestamp=D::Timestamp> + Debug,
243 D: BusDevice,
244 D::Timestamp: Debug + Copy
245{
246 type Timestamp = D::Timestamp;
247 type NextDevice = D;
248
249 #[inline]
250 fn next_device_mut(&mut self) -> &mut Self::NextDevice {
251 &mut self.bus
252 }
253
254 #[inline]
255 fn next_device_ref(&self) -> &Self::NextDevice {
256 &self.bus
257 }
258
259 #[inline]
260 fn into_next_device(self) -> Self::NextDevice {
261 self.bus
262 }
263
264 #[inline]
265 fn reset(&mut self, timestamp: Self::Timestamp) {
266 self.ay_sound.reset();
267 self.ay_io.reset(timestamp);
268 self.bus.reset(timestamp);
269 }
270
271 #[inline]
272 fn read_io(&mut self, port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
273 if P::is_data_read(port) {
274 return Some((self.ay_io.data_port_read(port, timestamp), None))
275 }
276 self.bus.read_io(port, timestamp)
277 }
278
279 #[inline]
280 fn write_io(&mut self, port: u16, data: u8, timestamp: Self::Timestamp) -> Option<u16> {
281 if P::write_ay_io(&mut self.ay_io, port, data, timestamp) {
282 return Some(0)
283 }
284 self.bus.write_io(port, data, timestamp)
285 }
286
287 #[inline]
288 fn next_frame(&mut self, timestamp: Self::Timestamp) {
289 if !self.ay_io.recorder.is_empty() {
295 for (reg, val) in self.ay_io.iter_sound_gen_regs() {
296 self.ay_sound.update_register(reg, val);
297 }
298 }
299 self.ay_io.next_frame(timestamp);
300 self.bus.next_frame(timestamp)
301 }
302}