1 #include "resampler.hpp"
8 uint64_t next_sample_time(uint64_t time
, uint32_t rate
)
10 uint64_t seconds
= time
/ 1000000000;
11 uint64_t subseconds
= time
% 1000000000;
12 uint64_t subsamples
= (rate
* subseconds
+ 999999999) / 1000000000;
13 subseconds
= 1000000000 * subsamples
/ rate
;
14 return seconds
* 1000000000 + subseconds
;
17 npair
<int64_t> widen(npair
<short> x
)
19 return npair
<int64_t>(x
.get_x(), x
.get_y());
22 sample_number_t
narrow(npair
<int64_t> x
)
24 return sample_number_t((sample_number_t::base_type
)(x
.get_x()), (sample_number_t::base_type
)(x
.get_y()));
27 resampler::~resampler()
31 resampler_pcm::resampler_pcm(uint32_t rate
)
37 sample_number_t
resampler_pcm::nextsample()
40 return sample_number_t(0, 0);
42 uint64_t now
= next_sample_time(last_read_time
+ 1, output_rate
);
43 if(last_write_time
<= last_read_time
) {
45 last_write_time
= now
;
46 accumulator
= npair
<int64_t>::zero();
47 return current_levels
;
50 int64_t cover
= now
- last_read_time
;
54 accumulator
= npair
<int64_t>::zero();
55 return current_levels
;
58 uint64_t wcover
= now
- last_write_time
;
59 accumulator
= accumulator
+ widen(current_levels
) * wcover
;
60 last_write_time
= now
;
61 npair
<int64_t> avg
= accumulator
/ cover
;
62 accumulator
= npair
<int64_t>::zero();
66 void resampler_pcm::sendpacket(struct packet
& p
)
68 if(p
.rp_major
!= 1 || p
.rp_minor
!= 1 || p
.rp_payload
.size() < 4)
72 cover
= p
.rp_timestamp
- last_write_time
;
74 last_read_time
= p
.rp_timestamp
;
76 accumulator
= accumulator
+ cover
* widen(current_levels
);
77 unsigned char* pl
= &p
.rp_payload
[0];
78 current_levels
= npair
<short>((unsigned short)pl
[0] * 256 + (unsigned short)pl
[1],
79 (unsigned short)pl
[2] * 256 + (unsigned short)pl
[3]);
80 last_write_time
= p
.rp_timestamp
;
83 resampler_fm::resampler_fm(uint32_t rate
)
88 sample_number_t
resampler_fm::nextsample()
91 adlib_getsample(samples
, 1);
92 return sample_number_t(samples
[0], samples
[1]);
95 void resampler_fm::sendpacket(struct packet
& p
)
99 if(p
.rp_minor
== 0 || p
.rp_minor
> 3)
100 return; //Wrong type.
101 if((p
.rp_minor
== 1 || p
.rp_minor
== 2) && p
.rp_payload
.size() < 2)
104 if(p
.rp_minor
== 3) {
106 for(int i
= 0; i
< 512; i
++)
111 unsigned short reg
= p
.rp_payload
[0];
112 unsigned char val
= p
.rp_payload
[1];
114 reg
+= 256; //Second set.
115 adlib_write(reg
, val
);
119 packet_demux::packet_demux(mixer
& mix
, uint32_t rate
)
123 output_filter
= new composite_filter();
124 use_mixer
.set_output_filter(*output_filter
);
127 packet_demux::~packet_demux()
129 for(std::map
<uint32_t, resampler
*>::iterator i
= resamplers
.begin(); i
!= resamplers
.end(); ++i
)
134 sample_number_t
packet_demux::nextsample()
136 for(std::map
<uint32_t, resampler
*>::iterator i
= resamplers
.begin(); i
!= resamplers
.end(); ++i
)
137 use_mixer
.send_sample(i
->first
, i
->second
->nextsample());
138 return use_mixer
.recv_sample();
141 void packet_demux::do_volume_change(struct packet
& p
)
143 filter_number_t::base_type lv
, rv
;
144 uint32_t ln
= 0, ld
= 0, rn
= 0, rd
= 0;
145 if(p
.rp_payload
.size() < 16)
148 ln
|= (uint32_t)p
.rp_payload
[0] << 24;
149 ln
|= (uint32_t)p
.rp_payload
[1] << 16;
150 ln
|= (uint32_t)p
.rp_payload
[2] << 8;
151 ln
|= (uint32_t)p
.rp_payload
[3];
152 ld
|= (uint32_t)p
.rp_payload
[4] << 24;
153 ld
|= (uint32_t)p
.rp_payload
[5] << 16;
154 ld
|= (uint32_t)p
.rp_payload
[6] << 8;
155 ld
|= (uint32_t)p
.rp_payload
[7];
156 rn
|= (uint32_t)p
.rp_payload
[8] << 24;
157 rn
|= (uint32_t)p
.rp_payload
[9] << 16;
158 rn
|= (uint32_t)p
.rp_payload
[10] << 8;
159 rn
|= (uint32_t)p
.rp_payload
[11];
160 rd
|= (uint32_t)p
.rp_payload
[12] << 24;
161 rd
|= (uint32_t)p
.rp_payload
[13] << 16;
162 rd
|= (uint32_t)p
.rp_payload
[14] << 8;
163 rd
|= (uint32_t)p
.rp_payload
[15];
168 lv
= (filter_number_t::base_type
)ln
/ ld
;
169 rv
= (filter_number_t::base_type
)rn
/ rd
;
170 use_mixer
.set_channel_volume(p
.rp_channel_perm
, filter_number_t(lv
, rv
));
173 void packet_demux::sendpacket(struct packet
& p
)
175 if(p
.rp_major
!= 1 && p
.rp_major
!= 2)
176 return; //Not interested.
177 if(p
.rp_minor
== 0) {
179 return; //Volume change.
181 if(!resamplers
.count(p
.rp_channel_perm
)) {
183 resamplers
[p
.rp_channel_perm
] = new resampler_pcm(used_rate
);
184 else if(p
.rp_major
== 2)
185 resamplers
[p
.rp_channel_perm
] = new resampler_fm(used_rate
);
186 if(input_filters
.count(p
.rp_channel_name
))
187 use_mixer
.set_input_filter(p
.rp_channel_perm
, *input_filters
[p
.rp_channel_name
]);
189 resamplers
[p
.rp_channel_perm
]->sendpacket(p
);
192 std::vector
<filter_number_t
> process_filter(std::string spec
)
194 std::vector
<filter_number_t
> f
;
197 throw std::runtime_error("Bad filter specification");
199 const char* o
= spec
.c_str();
200 double val
= strtod(o
, &x
);
202 throw std::runtime_error("Bad filter specification");
203 f
.push_back(filter_number_t(val
, val
));
206 spec
= spec
.substr(x
+ 1 - o
);
211 void packet_demux::sendoption(const std::string
& option
)
213 std::string _option
= option
;
214 std::string optionname
;
215 bool on_output
= false;
216 std::string optionchan
;
217 std::string optionvalue
;
218 struct filter
* f
= NULL
;
219 if(option
== "silence") {
222 } else if(isstringprefix(option
, "silence=")) {
223 optionchan
= settingvalue(option
);
226 optionvalue
= settingvalue(option
);
227 size_t spos
= optionvalue
.find_first_of(":");
228 if(spos
> optionvalue
.length())
231 optionchan
= optionvalue
.substr(0, spos
);
232 optionvalue
= optionvalue
.substr(spos
+ 1);
234 if(isstringprefix(option
, "gain=")) {
236 double gdb
= strtod(optionvalue
.c_str(), &x
);
238 throw std::runtime_error("Bad value");
239 f
= new amplifier(gdb
, AMPLIFIER_GAIN_DB
);
240 } else if(isstringprefix(option
, "attenuate=")) {
242 double gdb
= strtod(optionvalue
.c_str(), &x
);
244 throw std::runtime_error("Bad value");
245 f
= new amplifier(gdb
, AMPLIFIER_ATTENUATION_DB
);
246 } else if(isstringprefix(option
, "filter=")) {
247 size_t spos
= optionvalue
.find_first_of(";");
248 if(spos
> optionvalue
.length())
249 f
= new digital_filter(process_filter(optionvalue
));
251 f
= new digital_filter(process_filter(optionvalue
.substr(0, spos
)),
252 process_filter(optionvalue
.substr(spos
+ 1)));
254 throw std::runtime_error("Unknown audio processing option");
258 output_filter
->add(*f
);
260 if(!input_filters
.count(optionchan
))
261 input_filters
[optionchan
] = new composite_filter();
262 input_filters
[optionchan
]->add(*f
);
266 composite_filter
* output_filter
;
267 std::map
<std::string
, composite_filter
*> input_filters
;
271 --audio-fir=[<channel>:]<a0>,<a1>,...
272 Perform FIR filitering (y0 = a0*x0 + a1*x1 + ... + an*xn).
273 --audio-iir=[<channel>:]<a0>,<a1>,...;<b0>,<b1>,...
274 Perform FIR filitering (b0*y0 + b1*y1 + ... bm*ym = a0*x0 + a1*x1 + ... + an*xn).
275 --audio-attenuate=[<channel>:]<amount>
276 Attenuate sound by <amount> decibels.
277 --audio-gain=[<channel>:]<amount>
278 Amplify sound by <amount> decibels.
281 void print_audio_resampler_help(const std::string
& prefix
)
283 std::cout
<< prefix
<< "filter=[<channel>:]<a0>,<a1>,..." << std::endl
;
284 std::cout
<< "\tPreform FIR filtering (y0 = a0*x0 + a1*x1 + ... + an*xn)." << std::endl
;
285 std::cout
<< prefix
<< "filter=[<channel>:]<a0>,<a1>,...;<b0>,<b1>,..." << std::endl
;
286 std::cout
<< "\tPreform IIR filtering (b0*y0 + b1*y1 + ... bm*ym = a0*x0 + a1*x1 + ... + an*xn)." << std::endl
;
287 std::cout
<< prefix
<< "gain=[<channel>:]<decibels>" << std::endl
;
288 std::cout
<< "\tAmplify signal by <decibels> dB." << std::endl
;
289 std::cout
<< prefix
<< "attenuate=[<channel>:]<decibels>" << std::endl
;
290 std::cout
<< "\tAttenuate signal by <decibels> dB." << std::endl
;
291 std::cout
<< prefix
<< "silence" << std::endl
;
292 std::cout
<< "\tCompletely silence audio output." << std::endl
;
293 std::cout
<< prefix
<< "silence=<channel>" << std::endl
;
294 std::cout
<< "\tCompletely silence audio output on channel." << std::endl
;
297 void process_audio_resampler_options(packet_demux
& d
, const std::string
& prefix
, int argc
, char** argv
)
299 for(int i
= 1; i
< argc
; i
++) {
300 std::string arg
= argv
[i
];
303 if(!isstringprefix(arg
, prefix
))
306 d
.sendoption(arg
.substr(prefix
.length()));
307 } catch(std::exception
& e
) {
308 std::stringstream str
;
309 str
<< "Error processing option '" << arg
<< "': " << e
.what();
310 throw std::runtime_error(str
.str());