Add user interaction
This commit is contained in:
45
src/main.rs
45
src/main.rs
@@ -3,10 +3,10 @@ use std::{fs::File, io::BufReader};
|
|||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use telegram_bot::CanReplySendMessage;
|
|
||||||
use telegram_bot::{
|
use telegram_bot::{
|
||||||
Api, CanGetFile, CanReplySendAudio, InputFileUpload, MessageKind, UpdateKind, Voice,
|
Api, CanGetFile, CanReplySendAudio, InputFileUpload, MessageKind, UpdateKind, Voice,
|
||||||
};
|
};
|
||||||
|
use telegram_bot::{CanDeleteMessage, CanReplySendMessage};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
@@ -43,6 +43,8 @@ enum RuntimeError {
|
|||||||
FileDecodeError(#[source] ogg_opus::Error),
|
FileDecodeError(#[source] ogg_opus::Error),
|
||||||
#[error("Cannot encode audio file")]
|
#[error("Cannot encode audio file")]
|
||||||
FileEncodeError(#[source] ogg_opus::Error),
|
FileEncodeError(#[source] ogg_opus::Error),
|
||||||
|
#[error("The voice message does not contain any audio data")]
|
||||||
|
FileAudioEmpty,
|
||||||
#[error("Internal error")]
|
#[error("Internal error")]
|
||||||
IOError(#[from] std::io::Error),
|
IOError(#[from] std::io::Error),
|
||||||
}
|
}
|
||||||
@@ -70,21 +72,39 @@ async fn main() -> Result<(), UnresolvableError> {
|
|||||||
// If the received update contains a new message...
|
// If the received update contains a new message...
|
||||||
let update = update?;
|
let update = update?;
|
||||||
if let UpdateKind::Message(message) = update.kind {
|
if let UpdateKind::Message(message) = update.kind {
|
||||||
if let MessageKind::Voice { data } = &message.kind {
|
match &message.kind {
|
||||||
|
MessageKind::Voice { data } => {
|
||||||
|
let progress_message = api
|
||||||
|
.send(message.text_reply("On it, give me a sec..."))
|
||||||
|
.await?;
|
||||||
let result = handle_voice_message(&config, &api, data).await;
|
let result = handle_voice_message(&config, &api, data).await;
|
||||||
match result {
|
match result {
|
||||||
Ok(audio) => {
|
Ok(audio) => {
|
||||||
api.send(
|
api.send(
|
||||||
message.audio_reply(InputFileUpload::with_data(audio, "amplified.ogg")),
|
message.audio_reply(InputFileUpload::with_data(
|
||||||
|
audio,
|
||||||
|
"amplified.ogg",
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{:?}", err);
|
match err {
|
||||||
|
RuntimeError::FileAudioEmpty => {}
|
||||||
|
_ => error!("{:?}", err),
|
||||||
|
}
|
||||||
api.send(message.text_reply(format!("Error: {}", err)))
|
api.send(message.text_reply(format!("Error: {}", err)))
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
api.send(progress_message.delete()).await?;
|
||||||
|
}
|
||||||
|
MessageKind::Text { data, .. } => {
|
||||||
|
if data.starts_with("/") {
|
||||||
|
api.send(message.text_reply("Send or forward voicemessages to me and I'll amplify them for you. Currently, I don't understand any commands.")).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,7 +145,7 @@ async fn handle_voice_message(
|
|||||||
let mut last_audio = audio.clone();
|
let mut last_audio = audio.clone();
|
||||||
let mut amplification_factor = 2;
|
let mut amplification_factor = 2;
|
||||||
loop {
|
loop {
|
||||||
let (current_audio, clipping_rate) = amplify_audio(&audio, amplification_factor);
|
let (current_audio, clipping_rate) = amplify_audio(&audio, amplification_factor)?;
|
||||||
if clipping_rate > 1.0 / (48000.0 * 10.0) {
|
if clipping_rate > 1.0 / (48000.0 * 10.0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -141,17 +161,26 @@ async fn handle_voice_message(
|
|||||||
Ok(ogg_data_out)
|
Ok(ogg_data_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn amplify_audio(original: &[i16], factor: i16) -> (Vec<i16>, f64) {
|
fn amplify_audio(original: &[i16], factor: i16) -> Result<(Vec<i16>, f64), RuntimeError> {
|
||||||
|
let mut is_empty = true;
|
||||||
let mut modified_audio = original.to_owned();
|
let mut modified_audio = original.to_owned();
|
||||||
let mut clipping_samples = 0;
|
let mut clipping_samples = 0;
|
||||||
for sample in modified_audio.iter_mut() {
|
for sample in modified_audio.iter_mut() {
|
||||||
|
if *sample == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
is_empty = false;
|
||||||
*sample = sample.checked_mul(factor).unwrap_or_else(|| {
|
*sample = sample.checked_mul(factor).unwrap_or_else(|| {
|
||||||
clipping_samples += 1;
|
clipping_samples += 1;
|
||||||
sample.saturating_mul(factor)
|
sample.saturating_mul(factor)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_empty {
|
||||||
|
return Err(RuntimeError::FileAudioEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
let clipping_rate = clipping_samples as f64 / modified_audio.len() as f64;
|
let clipping_rate = clipping_samples as f64 / modified_audio.len() as f64;
|
||||||
info!("samples: {} rate: {}", clipping_samples, clipping_rate);
|
trace!("samples: {} rate: {}", clipping_samples, clipping_rate);
|
||||||
(modified_audio, clipping_rate)
|
Ok((modified_audio, clipping_rate))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user