From c5fe2af6da0ff8931fa9845183c2b9537c5d46ac Mon Sep 17 00:00:00 2001 From: Ravachol Date: Sun, 24 Mar 2024 18:53:32 +0800 Subject: [PATCH 1/2] replaced pure noise with a mix of sine wave and noise --- app/services/audio_service.py | 56 +++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/app/services/audio_service.py b/app/services/audio_service.py index d4c50be..a255542 100644 --- a/app/services/audio_service.py +++ b/app/services/audio_service.py @@ -5,9 +5,24 @@ import struct import uuid import ffmpeg +import math from configs import config +SAMPLE_RATE = 8000 + +# generate a noise sample +def noise_sample(): + sample = random.randint(-32768, 32767) + sample_packed = struct.pack('h', sample) + return sample_packed + +# generate a sine wave sample +def sine_sample(freq, volume, x): + value = volume * math.sin(2 * math.pi * freq * (x / SAMPLE_RATE)) + sample = int(value * 32767.0) + return struct.pack('h', sample) + # Generate random audio in .wav def generate_random_audio(): # filename @@ -15,23 +30,38 @@ def generate_random_audio(): audio_path = config.AUDIO_DIR+"/"+name+".wav" # open file in write mode audio = wave.open(audio_path, "wb") - audio.setparams((2, 2, 44100, 0, 'NONE', 'not compressed')) + audio.setparams((2, 2, 24000, 0, 'NONE', 'not compressed')) values = [] - # length of the audio (in chunks) - len = random.randint(20, 60) - # generate the content of the audio + len = random.randint(8, 10) + + # generate a mix of sine wave and noise for i in range(0, len): - v1 = random.randint(-32768, 32768) - v2 = random.randint(-32768, 32768) - v1_packed = struct.pack('h', v1) - v2_packed = struct.pack('h', v2) - # chunk duration - duration = random.randint(1000, 10000) - for j in range(0, duration): - values.append(v1_packed) - values.append(v2_packed) + # two channels + freq_channel_1 = random.randint(20, 1000) + freq_channel_2 = random.randint(20, 1000) + # duration of every chunk in seconds + chunk_duration = random.uniform(1, 2) + # volume + volume_channel_1 = random.uniform(0.5, 1.0) + volume_channel_2 = random.uniform(0.5, 1.0) + # build the chunk + for x in range(0, 2 * SAMPLE_RATE): + sine_channel_1 = sine_sample(freq_channel_1, volume_channel_1, x) + sine_channel_2 = sine_sample(freq_channel_2, volume_channel_2, x) + noise = noise_sample() + # channel 1 + if random.choice([True, False]): + values.append(sine_channel_1) + else: + values.append(noise) + # channel 2 + if random.choice([True, False]): + values.append(sine_channel_2) + else: + values.append(noise) + # make a byte string values_str = b''.join(values) # write into the file From 6ab0710cf7076fd6c1d0fc7030f0e7a38d440b21 Mon Sep 17 00:00:00 2001 From: Ravachol Date: Mon, 25 Mar 2024 14:59:21 +0800 Subject: [PATCH 2/2] seperated the audio generaters --- app/handlers/audio_handler.py | 27 ++++++++++--- app/handlers/inline_handler.py | 2 +- app/services/audio_service.py | 71 +++++++++++++++++++++++++++++----- bot.py | 26 ++++++++----- tests/audio_test.py | 18 +++++++-- 5 files changed, 115 insertions(+), 29 deletions(-) diff --git a/app/handlers/audio_handler.py b/app/handlers/audio_handler.py index 46f0de3..6b64746 100644 --- a/app/handlers/audio_handler.py +++ b/app/handlers/audio_handler.py @@ -3,16 +3,33 @@ from telebot import TeleBot from telebot.types import Message -from app.services.audio_service import generate_random_audio +from app.services.audio_service import generate_random_noise +from app.services.audio_service import generate_random_sine +from app.services.audio_service import generate_random_mix from app.services.audio_service import generate_random_voice -# invoke with "/random_audio" command -def get_random_audio(message: Message, bot: TeleBot): +# invoke with "/noise" command +def get_random_noise(message: Message, bot: TeleBot): # pretend to be uploading audio bot.send_chat_action(message.chat.id, "upload_voice") - audio = generate_random_audio() - bot.send_audio(message.chat.id, audio) + noise = generate_random_noise() + bot.send_audio(message.chat.id, noise) +# invoke with "/sine" command +def get_random_sine(message: Message, bot: TeleBot): + # uploading audio... + bot.send_chat_action(message.chat.id, "upload_voice") + sine = generate_random_sine() + bot.send_audio(message.chat.id, sine) + +# invoke with "/mix" command +def get_random_mix(message: Message, bot: TeleBot): + # uploading audio... + bot.send_chat_action(message.chat.id, "upload_voice") + mix = generate_random_mix() + bot.send_audio(message.chat.id, mix) + +# invoke with "/voice" command def get_random_voice(message: Message, bot: TeleBot): # pretend to be sending voice bot.send_chat_action(message.chat.id, "record_voice") diff --git a/app/handlers/inline_handler.py b/app/handlers/inline_handler.py index 1f02e75..90026b5 100644 --- a/app/handlers/inline_handler.py +++ b/app/handlers/inline_handler.py @@ -4,7 +4,7 @@ from telebot import types from app.services.text_service import generate_random_text -from app.services.audio_service import generate_random_audio +from app.services.audio_service import generate_random_mix def inline_dispatch(inline_query, bot: TeleBot): try: diff --git a/app/services/audio_service.py b/app/services/audio_service.py index a255542..9ade156 100644 --- a/app/services/audio_service.py +++ b/app/services/audio_service.py @@ -1,4 +1,5 @@ # audio_service +# TODO: ugly code !!!! import wave import random @@ -10,6 +11,10 @@ from configs import config SAMPLE_RATE = 8000 +FREQ_HIGH = 800 +FREQ_LOW = 20 +VOLUME_HIGH = 0.7 +VOLUME_LOW = 0.3 # generate a noise sample def noise_sample(): @@ -23,11 +28,59 @@ def sine_sample(freq, volume, x): sample = int(value * 32767.0) return struct.pack('h', sample) +# Generate a noise +def generate_random_noise(): + name = uuid.uuid4().hex + audio_path = config.AUDIO_DIR+"/noise_"+name+".wav" + audio = wave.open(audio_path, "wb") + audio.setparams((2, 2, 24000, 0, 'NONE', 'not compressed')) + len = random.randint(20, 60) + values = [] + # build the noise + for i in range(0, len): + channel_1 = noise_sample() + channel_2 = noise_sample() + chunk_duration = random.randint(1000, 10000) + for j in range(0, chunk_duration): + values.append(channel_1) + values.append(channel_2) + + # make a byte string + values_str = b''.join(values) + audio.writeframes(values_str) + audio.close() + return open(audio_path, "rb") + +# Generate a sine wave audio +def generate_random_sine(): + name = uuid.uuid4().hex + audio_path = config.AUDIO_DIR+"/sine_"+name+".wav" + audio = wave.open(audio_path, "wb") + audio.setparams((2, 2, 24000, 0, 'NONE', 'not compressed')) + + values = [] + + len = random.randint(8, 10) + for i in range(0, len): + freq = random.randint(FREQ_LOW, FREQ_HIGH) + chunk_duration = random.randint(1, 2) + volume = random.uniform(VOLUME_LOW, VOLUME_HIGH) + for x in range(0, chunk_duration * SAMPLE_RATE): + sine = sine_sample(freq, volume, x) + values.append(sine) + values.append(sine) + + values_str = b''.join(values) + audio.writeframes(values_str) + audio.close + return open(audio_path, "rb") + + # Generate random audio in .wav -def generate_random_audio(): +def generate_random_mix(): # filename name = uuid.uuid4().hex - audio_path = config.AUDIO_DIR+"/"+name+".wav" + audio_path = config.AUDIO_DIR+"/mix_"+name+".wav" # open file in write mode audio = wave.open(audio_path, "wb") audio.setparams((2, 2, 24000, 0, 'NONE', 'not compressed')) @@ -39,15 +92,15 @@ def generate_random_audio(): # generate a mix of sine wave and noise for i in range(0, len): # two channels - freq_channel_1 = random.randint(20, 1000) - freq_channel_2 = random.randint(20, 1000) + freq_channel_1 = random.randint(FREQ_LOW, FREQ_HIGH) + freq_channel_2 = random.randint(FREQ_LOW, FREQ_HIGH) # duration of every chunk in seconds - chunk_duration = random.uniform(1, 2) + chunk_duration = random.randint(1, 2) # volume - volume_channel_1 = random.uniform(0.5, 1.0) - volume_channel_2 = random.uniform(0.5, 1.0) + volume_channel_1 = random.uniform(VOLUME_LOW, VOLUME_HIGH) + volume_channel_2 = random.uniform(VOLUME_LOW, VOLUME_HIGH) # build the chunk - for x in range(0, 2 * SAMPLE_RATE): + for x in range(0, chunk_duration * SAMPLE_RATE): sine_channel_1 = sine_sample(freq_channel_1, volume_channel_1, x) sine_channel_2 = sine_sample(freq_channel_2, volume_channel_2, x) noise = noise_sample() @@ -74,7 +127,7 @@ def generate_random_audio(): # generate random voice in .ogg by converting .wav file def generate_random_voice(): # generate a random wav file - wavfile = generate_random_audio() + wavfile = generate_random_mix() # file name of the generated .ogg oggfile = wavfile.name+".ogg" # convert with ffmpeg diff --git a/bot.py b/bot.py index b4258e2..b6613aa 100644 --- a/bot.py +++ b/bot.py @@ -7,7 +7,9 @@ from app.handlers.info_handler import get_info from app.handlers.text_handler import get_random_text from app.handlers.text_handler import get_random_text_mono -from app.handlers.audio_handler import get_random_audio +from app.handlers.audio_handler import get_random_noise +from app.handlers.audio_handler import get_random_sine +from app.handlers.audio_handler import get_random_mix from app.handlers.audio_handler import get_random_voice from app.handlers.inline_handler import inline_dispatch @@ -20,10 +22,12 @@ def commands(): bot.set_my_commands([ telebot.types.BotCommand("help", "Get info"), - telebot.types.BotCommand("random", "Random text"), - telebot.types.BotCommand("random_mono", "Monospace random text"), - telebot.types.BotCommand("random_audio", "Random audio"), - telebot.types.BotCommand("random_voice", "Random voice") + telebot.types.BotCommand("text", "Random text"), + telebot.types.BotCommand("mono", "Monospace random text"), + telebot.types.BotCommand("noise", "Random noise"), + telebot.types.BotCommand("sine", "Random sine wave audio"), + telebot.types.BotCommand("mix", "Random mix"), + telebot.types.BotCommand("voice", "Random voice") ]) commands() @@ -32,12 +36,14 @@ def handlers(): # info bot.register_message_handler(get_info, commands=['start', 'help'], pass_bot=True) # random text - bot.register_message_handler(get_random_text, commands=['random'], pass_bot=True) - bot.register_message_handler(get_random_text_mono, commands=['random_mono'], pass_bot=True) + bot.register_message_handler(get_random_text, commands=['text'], pass_bot=True) + bot.register_message_handler(get_random_text_mono, commands=['mono'], pass_bot=True) # random audio - bot.register_message_handler(get_random_audio, commands=['random_audio'], pass_bot=True) - # random voice - bot.register_message_handler(get_random_voice, commands=['random_voice'], pass_bot=True) + bot.register_message_handler(get_random_noise, commands=['noise'], pass_bot=True) + bot.register_message_handler(get_random_sine, commands=['sine'], pass_bot=True) + bot.register_message_handler(get_random_mix, commands=['mix'], pass_bot=True) + # random voice (a mix of noise and sine wave sent as voice) + bot.register_message_handler(get_random_voice, commands=['voice'], pass_bot=True) # inline bot.register_inline_handler(inline_dispatch, lambda query: query, pass_bot=True) diff --git a/tests/audio_test.py b/tests/audio_test.py index 9fe35b3..eb9aec6 100644 --- a/tests/audio_test.py +++ b/tests/audio_test.py @@ -2,12 +2,22 @@ import io -from app.services.audio_service import generate_random_audio +from app.services.audio_service import generate_random_noise +from app.services.audio_service import generate_random_sine +from app.services.audio_service import generate_random_mix from app.services.audio_service import generate_random_voice -def test_audio_generated(): - audio = generate_random_audio() - assert isinstance(audio, io.BufferedIOBase) +def test_noise_generated(): + noise = generate_random_noise() + assert isinstance(noise, io.BufferedIOBase) + +def test_sine_generated(): + sine = generate_random_sine() + assert isinstance(sine, io.BufferedIOBase) + +def test_mix_generated(): + mix = generate_random_mix() + assert isinstance(mix, io.BufferedIOBase) def test_voice_generated(): voice = generate_random_voice()