summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/spkrdev.h
blob: b7d0ac95cec504f0e21f061d4899c5c01871e2b6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// 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_SOUND_SPKRDEV_H
#define MAME_SOUND_SPKRDEV_H

#pragma once


#define MCFG_SPEAKER_LEVELS(_num, _levels) \
	downcast<speaker_sound_device &>(*device).set_levels(_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 = 0);
	~speaker_sound_device() {}

	// configuration
	void set_levels(int num_levels, const int16_t *levels) { m_num_levels = num_levels; 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:
	// Length of anti-aliasing filter kernel, measured in number of intermediate samples
	enum
	{
		FILTER_LENGTH = 64
	};

	// 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 */
};

DECLARE_DEVICE_TYPE(SPEAKER_SOUND, speaker_sound_device)

#endif // MAME_SOUND_SPKRDEV_H