1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * Copyright (C) 2020-2021 The DOSBox Staging Team
5 * Copyright (C) 2002-2021 The DOSBox Team
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #ifndef DOSBOX_MIXER_H
23 #define DOSBOX_MIXER_H
24
25 #include "dosbox.h"
26
27 #include <atomic>
28 #include <functional>
29 #include <memory>
30
31 #include "envelope.h"
32
33 typedef void (*MIXER_MixHandler)(Bit8u *sampdate, Bit32u len);
34
35 // The mixer callback can accept a static function or a member function
36 // using a std::bind. The callback typically requests enough frames to
37 // fill one millisecond with of audio. For an audio channel running at
38 // 48000 Hz, that's 48 frames.
39 using MIXER_Handler = std::function<void(uint16_t frames)>;
40
41 enum BlahModes {
42 MIXER_8MONO,MIXER_8STEREO,
43 MIXER_16MONO,MIXER_16STEREO
44 };
45
46 enum MixerModes {
47 M_8M,M_8S,
48 M_16M,M_16S
49 };
50
51 // A simple stereo audio frame
52 struct AudioFrame {
53 float left = 0;
54 float right = 0;
55 };
56
57 #define MIXER_BUFSIZE (16 * 1024)
58 #define MIXER_BUFMASK (MIXER_BUFSIZE - 1)
59 extern Bit8u MixTemp[MIXER_BUFSIZE];
60
61 #define MAX_AUDIO ((1<<(16-1))-1)
62 #define MIN_AUDIO -(1<<(16-1))
63
64 // Get a DOS-formatted silent-sample when there's a chance it will
65 // be processed using AddSamples_nonnative()
66 template <typename T>
Mixer_GetSilentDOSSample()67 constexpr T Mixer_GetSilentDOSSample()
68 {
69 // All signed samples are silent at true zero
70 if (std::is_signed<T>::value)
71 return static_cast<T>(0);
72
73 // unsigned 8-bit samples: silence is always 128
74 constexpr bool is_multibyte = sizeof(T) > 1;
75 if (!is_multibyte)
76 return static_cast<T>(128);
77
78 // unsigned 16-bit samples: silence is always 32768 (little-endian)
79 if (sizeof(T) == 2u)
80 #if defined(WORDS_BIGENDIAN)
81 return static_cast<T>(0x0080); // 32768 (little-endian)
82 #else
83 return static_cast<T>(0x8000); // 32768
84 #endif
85 static_assert(sizeof(T) <= 2, "DOS only produced 8 and 16-bit samples");
86 }
87
88 class MixerChannel {
89 public:
90 MixerChannel(MIXER_Handler _handler, const char *name);
91 int GetSampleRate() const;
92 bool IsInterpolated() const;
93 using apply_level_callback_f = std::function<void(const AudioFrame &level)>;
94 void RegisterLevelCallBack(apply_level_callback_f cb);
95 void SetVolume(float _left, float _right);
96 void SetScale(float f);
97 void SetScale(float _left, float _right);
98 void MapChannels(Bit8u _left, Bit8u _right);
99 void UpdateVolume();
100 void SetFreq(int _freq);
101 void SetPeakAmplitude(int peak);
102 void Mix(int _needed);
103 void AddSilence(); // Fill up until needed
104
105 template <class Type, bool stereo, bool signeddata, bool nativeorder>
106 void AddSamples(uint16_t len, const Type *data);
107
108 void AddSamples_m8(uint16_t len, const Bit8u *data);
109 void AddSamples_s8(uint16_t len, const Bit8u *data);
110 void AddSamples_m8s(uint16_t len, const Bit8s *data);
111 void AddSamples_s8s(uint16_t len, const Bit8s *data);
112 void AddSamples_m16(uint16_t len, const Bit16s *data);
113 void AddSamples_s16(uint16_t len, const Bit16s *data);
114 void AddSamples_m16u(uint16_t len, const Bit16u *data);
115 void AddSamples_s16u(uint16_t len, const Bit16u *data);
116 void AddSamples_m32(uint16_t len, const Bit32s *data);
117 void AddSamples_s32(uint16_t len, const Bit32s *data);
118 void AddSamples_m16_nonnative(uint16_t len, const Bit16s *data);
119 void AddSamples_s16_nonnative(uint16_t len, const Bit16s *data);
120 void AddSamples_m16u_nonnative(uint16_t len, const Bit16u *data);
121 void AddSamples_s16u_nonnative(uint16_t len, const Bit16u *data);
122 void AddSamples_m32_nonnative(uint16_t len, const Bit32s *data);
123 void AddSamples_s32_nonnative(uint16_t len, const Bit32s *data);
124
125 void AddStretched(uint16_t len, Bit16s *data); // Stretch block up into needed data
126
127 void FillUp();
128 void Enable(bool should_enable);
129 void FlushSamples();
130
131 float volmain[2] = {1.0f, 1.0f};
132 std::atomic<int> done = 0; // Timing on how many samples have been done by the mixer
133 bool is_enabled = false;
134
135 private:
136 // prevent default construction, copying, and assignment
137 MixerChannel() = delete;
138 MixerChannel(const MixerChannel &) = delete;
139 MixerChannel &operator=(const MixerChannel &) = delete;
140
141 Envelope envelope;
142 MIXER_Handler handler = nullptr;
143 int freq_add = 0u; // This gets added the frequency counter each mixer step
144 int freq_counter = 0u; // When this flows over a new sample needs to be read from the device
145 int needed = 0u; // Timing on how many samples were needed by the mixer
146 int prev_sample[2] = {0, 0}; // Previous and next samples
147 int next_sample[2] = {0, 0};
148 // Simple way to lower the impact of DC offset. if MIXER_UPRAMP_STEPS is
149 // >0. Still work in progress and thus disabled for now.
150 int offset[2] = {0, 0};
151 int sample_rate = 0u;
152 int volmul[2] = {1, 1};
153 float scale[2] = {1.0f, 1.0f};
154
155 // Defines the peak sample amplitude we can expect in this channel.
156 // Default to signed 16bit max, however channel's that know their own
157 // peak, like the PCSpeaker, should update it with: SetPeakAmplitude()
158 int peak_amplitude = MAX_AUDIO;
159
160 uint8_t channel_map[2] = {0, 1}; // Output channel mapping
161
162 // The RegisterLevelCallBack() assigns this callback that can be used by
163 // the channel's source to manage the stream's level prior to mixing,
164 // in-place of scaling by volmain[]
165 apply_level_callback_f apply_level = nullptr;
166
167 bool interpolate = false;
168 bool last_samples_were_stereo = false;
169 bool last_samples_were_silence = true;
170 };
171 using mixer_channel_t = std::shared_ptr<MixerChannel>;
172
173 mixer_channel_t MIXER_AddChannel(MIXER_Handler handler, const int freq, const char *name);
174 mixer_channel_t MIXER_FindChannel(const char *name);
175
176 /* PC Speakers functions, tightly related to the timer functions */
177 void PCSPEAKER_SetCounter(int cntr, int mode);
178 void PCSPEAKER_SetType(int mode);
179
180 #endif
181