summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/spkrdev.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/spkrdev.h')
-rw-r--r--src/devices/sound/spkrdev.h95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/devices/sound/spkrdev.h b/src/devices/sound/spkrdev.h
new file mode 100644
index 00000000000..4fdb0a92ff6
--- /dev/null
+++ b/src/devices/sound/spkrdev.h
@@ -0,0 +1,95 @@
+// license:BSD-3-Clause
+// copyright-holders:Nicola Salmoria
+/**********************************************************************
+
+ speaker.h
+ Sound driver to emulate a simple speaker,
+ driven by one or more output bits
+
+**********************************************************************/
+#ifndef MAME_DEVICES_SOUND_SPKRDEV_H
+#define MAME_DEVICES_SOUND_SPKRDEV_H
+
+#pragma once
+
+
+// Length of anti-aliasing filter kernel, measured in number of intermediate samples
+enum
+{
+ FILTER_LENGTH = 64
+};
+
+#define MCFG_SPEAKER_LEVELS(_num, _levels) \
+ speaker_sound_device::static_set_levels(*device, _num, _levels);
+
+class speaker_sound_device : public device_t,
+ public device_sound_interface
+{
+public:
+ speaker_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ~speaker_sound_device() {}
+
+ // static configuration
+ static void static_set_levels(device_t &device, int num_levels, const int16_t *levels) { downcast<speaker_sound_device &>(device).m_num_levels = num_levels; downcast<speaker_sound_device &>(device).m_levels = levels;}
+
+ void level_w(int new_level);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+
+private:
+ // internal state
+
+ // Updates the composed volume array according to time
+ void update_interm_samples(const attotime &time, int volume);
+
+ // Updates the composed volume array and returns final filtered volume of next stream sample
+ double update_interm_samples_get_filtered_volume(int volume);
+
+ void finalize_interm_sample(int volume);
+ void init_next_interm_sample();
+ inline double make_fraction(const attotime &a, const attotime &b, double timediv);
+ double get_filtered_volume();
+
+ // Kernel (pulse response) for filtering across samples (while we avoid fancy filtering within samples)
+ double m_ampl[FILTER_LENGTH];
+
+ sound_stream *m_channel;
+ int m_level;
+
+ /* The volume of a composed sample grows incrementally each time the speaker is over-sampled.
+ * That is in effect a basic average filter.
+ * Another filter can and will be applied to the array of composed samples.
+ */
+ double m_composed_volume[FILTER_LENGTH]; /* integrator(s) */
+ int m_composed_sample_index; /* array index for composed_volume */
+ attoseconds_t m_channel_sample_period; /* in as */
+ double m_channel_sample_period_secfrac; /* in fraction of second */
+ attotime m_channel_last_sample_time;
+ attotime m_channel_next_sample_time;
+ attoseconds_t m_interm_sample_period;
+ double m_interm_sample_period_secfrac;
+ attotime m_next_interm_sample_time;
+ int m_interm_sample_index; /* counts interm. samples between stream samples */
+ attotime m_last_update_time; /* internal timestamp */
+
+ void speaker_postload();
+
+ // DC blocker state
+ double m_prevx, m_prevy;
+
+ int m_num_levels; /* optional: number of levels (if not two) */
+ const int16_t *m_levels; /* optional: pointer to level lookup table */
+};
+
+extern const device_type SPEAKER_SOUND;
+
+extern template class device_finder<speaker_sound_device, false>;
+extern template class device_finder<speaker_sound_device, true>;
+
+#endif // MAME_DEVICES_SOUND_SPKRDEV_H