}
}
-impl<T:Clone+Copy+From<u8>> AudioQueue<T> {
+trait ApplyVolume {
+ fn apply_volume(&mut self, vol: f32);
+}
+
+impl ApplyVolume for u8 {
+ fn apply_volume(&mut self, vol: f32) {
+ *self = (f32::from(*self) * vol).clamp(0.0, 255.0) as u8;
+ }
+}
+
+impl ApplyVolume for i16 {
+ fn apply_volume(&mut self, vol: f32) {
+ *self = (f32::from(*self) * vol).clamp(-32768.0, 32767.0) as i16;
+ }
+}
+
+impl ApplyVolume for i32 {
+ fn apply_volume(&mut self, vol: f32) {
+ *self = (f64::from(*self) * f64::from(vol)).clamp(-2147483648.0, 2147483647.0) as i32;
+ }
+}
+
+impl ApplyVolume for f32 {
+ fn apply_volume(&mut self, vol: f32) {
+ *self *= vol;
+ }
+}
+
+impl<T:Clone+Copy+From<u8>+ApplyVolume> AudioQueue<T> {
fn new(channels: usize, rec_size: usize, ileaved: bool) -> Self {
Self {
start: 0,
}
fn get_cur_avail(&self) -> usize { self.stride - self.end }
fn get_potentially_avail(&self) -> usize { self.stride - self.get_cur_size() }
- fn read(&mut self, src: &NAAudioBuffer<T>) {
+ fn read(&mut self, src: &NAAudioBuffer<T>, vol: f32) {
let mut to_copy = src.get_length();
if self.ileaved {
to_copy *= self.channels;
src.get_data().chunks(src.get_stride()))) {
dst[..old_len].copy_from_slice(&old[self.start..self.end]);
dst[old_len..][..new_len].copy_from_slice(&new[..new_len]);
+ if vol != 1.0 {
+ for el in dst[old_len..][..new_len].iter_mut() {
+ el.apply_volume(vol);
+ }
+ }
}
} else {
new_buf[..old_len].copy_from_slice(&self.data[self.start..self.end]);
copy_audio(&mut new_buf[old_len..], 1, src.get_data(), src.get_stride(), new_len, self.channels);
+ if vol != 1.0 {
+ for el in new_buf[old_len..][..new_len].iter_mut() {
+ el.apply_volume(vol);
+ }
+ }
}
} else {
copy_audio(&mut new_buf, if !self.ileaved { new_stride } else { 1 }, src.get_data(), src.get_stride(), new_len, self.channels);
+ if vol != 1.0 {
+ if self.ileaved {
+ for el in new_buf[..new_len].iter_mut() {
+ el.apply_volume(vol);
+ }
+ } else {
+ for channel in new_buf.chunks_exact_mut(new_stride) {
+ for el in channel[self.end..][..new_len / self.channels].iter_mut() {
+ el.apply_volume(vol);
+ }
+ }
+ }
+ }
}
self.data = new_buf;
self.stride = new_stride;
}
copy_audio(&mut self.data[self.end..], if !self.ileaved { self.stride } else { 1 }, src.get_data(), src.get_stride(),
to_copy, self.channels);
+ if vol != 1.0 {
+ if self.ileaved {
+ for el in self.data[self.end..][..to_copy].iter_mut() {
+ el.apply_volume(vol);
+ }
+ } else {
+ for channel in self.data.chunks_exact_mut(self.stride) {
+ for el in channel[self.end..][..to_copy / self.channels].iter_mut() {
+ el.apply_volume(vol);
+ }
+ }
+ }
+ }
self.end += to_copy;
}
fn write(&mut self, dbuf: &mut NAAudioBuffer<T>) {
resampler,
}
}
- pub fn queue_frame(&mut self, buf: NABufferType, tinfo: NATimeInfo) -> bool {
+ pub fn queue_frame(&mut self, buf: NABufferType, tinfo: NATimeInfo, vol: f32) -> bool {
let ret = self.resampler.convert_audio_frame(&buf);
if let Ok(dbuf) = ret {
if self.apts.is_none() && tinfo.get_pts().is_some() {
self.apts = tinfo.get_pts();
}
match (&mut self.queue, dbuf) {
- (AudioDataType::U8(ref mut queue), NABufferType::AudioU8(ref buf)) => queue.read(buf),
- (AudioDataType::I16(ref mut queue), NABufferType::AudioI16(ref buf)) => queue.read(buf),
- (AudioDataType::I32(ref mut queue), NABufferType::AudioI32(ref buf)) => queue.read(buf),
- (AudioDataType::F32(ref mut queue), NABufferType::AudioF32(ref buf)) => queue.read(buf),
- (AudioDataType::Packed(ref mut queue), NABufferType::AudioPacked(ref buf)) => queue.read(buf),
+ (AudioDataType::U8(ref mut queue), NABufferType::AudioU8(ref buf)) => queue.read(buf, vol),
+ (AudioDataType::I16(ref mut queue), NABufferType::AudioI16(ref buf)) => queue.read(buf, vol),
+ (AudioDataType::I32(ref mut queue), NABufferType::AudioI32(ref buf)) => queue.read(buf, vol),
+ (AudioDataType::F32(ref mut queue), NABufferType::AudioF32(ref buf)) => queue.read(buf, vol),
+ (AudioDataType::Packed(ref mut queue), NABufferType::AudioPacked(ref buf)) => queue.read(buf, vol),
_ => unimplemented!(),
};
true
pub enc_params: EncodeParameters,
pub enc_name: String,
pub enc_opts: Vec<OptionArgs>,
+ pub volume: f32,
}
pub struct DecodeContext {
pub cvt: Option<AudioConverter>,
pub sainfo: NAAudioInfo,
pub dainfo: NAAudioInfo,
+ pub vol: f32,
}
// todo better channel map generation
let cbuf = if let NABufferType::None = buf {
buf
} else if let Some(ref mut acvt) = self.cvt {
- if !acvt.queue_frame(buf, frm.get_time_information()) {
+ if !acvt.queue_frame(buf, frm.get_time_information(), self.vol) {
println!("error converting audio for stream {}", dst_id);
return Ok(false);
}
let sidx = if let Some(idx) = self.ostr_opts.iter().position(|el| el.id == streamno) {
idx
} else {
- self.ostr_opts.push(OutputStreamOptions {id: streamno, enc_name: String::new(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() });
+ self.ostr_opts.push(OutputStreamOptions {id: streamno, enc_name: String::new(), enc_params: EncodeParameters::default(), enc_opts: Vec::new(), volume: 1.0 });
self.ostr_opts.len() - 1
};
let ostr = &mut self.ostr_opts[sidx];
println!("invalid quality value");
}
},
+ "volume" => {
+ if let Ok(val) = oval[1].parse::<f32>() {
+ if (0.0..=1024.0).contains(&val) {
+ ostr.volume = val;
+ } else {
+ println!("invalid volume");
+ }
+ } else {
+ println!("invalid volume");
+ }
+ },
_ => {
ostr.enc_opts.push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) });
},
(NACodecTypeInfo::Audio(sainfo), NACodecTypeInfo::Audio(dainfo)) => {
let icodec = istr.get_info().get_name();
if (sainfo == dainfo) && (icodec != "pcm" || oopts.enc_name.as_str() == "pcm") {
- Box::new(AudioEncodeContext { encoder, cvt: None, sainfo: *sainfo, dainfo: *dainfo })
+ Box::new(AudioEncodeContext { encoder, cvt: None, sainfo: *sainfo, dainfo: *dainfo, vol: oopts.volume })
} else {
let dchmap = if let Some(ret) = generate_channel_map(dainfo) {
ret
return RegisterResult::Failed;
};
let acvt = AudioConverter::new(sainfo, dainfo, dchmap);
- Box::new(AudioEncodeContext { encoder, cvt: Some(acvt), sainfo: *sainfo, dainfo: *dainfo })
+ Box::new(AudioEncodeContext { encoder, cvt: Some(acvt), sainfo: *sainfo, dainfo: *dainfo, vol: oopts.volume })
}
},
_ => unreachable!(),
out_sm.add_stream((*istr).clone());
self.encoders.push(OutputMode::Copy(out_id));
} else {
- let mut oopts = OutputStreamOptions {id: out_id, enc_name: cname.to_owned(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() };
+ let mut oopts = OutputStreamOptions {id: out_id, enc_name: cname.to_owned(), enc_params: EncodeParameters::default(), enc_opts: Vec::new(), volume: 1.0 };
if let Some(ref profile) = self.profile {
match istr.get_media_type() {
}
}
if sainfo == &dainfo {
- Box::new(AudioEncodeContext { encoder, cvt: None, sainfo: *sainfo, dainfo })
+ Box::new(AudioEncodeContext { encoder, cvt: None, sainfo: *sainfo, dainfo, vol: oopts.volume })
} else {
let dchmap = if let Some(ret) = generate_channel_map(&dainfo) {
ret
return RegisterResult::Failed;
};
let acvt = AudioConverter::new(sainfo, &dainfo, dchmap);
- Box::new(AudioEncodeContext { encoder, cvt: Some(acvt), sainfo: *sainfo, dainfo })
+ Box::new(AudioEncodeContext { encoder, cvt: Some(acvt), sainfo: *sainfo, dainfo, vol: oopts.volume })
}
},
_ => unreachable!(),