Skip to content

Commit

Permalink
Merge pull request #12 from ravachol-yang/dev/sine
Browse files Browse the repository at this point in the history
replaced pure noise with a mix of sine wave and noise
  • Loading branch information
ravachol-yang authored Mar 25, 2024
2 parents b3b9423 + 6ab0710 commit 7811563
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 36 deletions.
27 changes: 22 additions & 5 deletions app/handlers/audio_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion app/handlers/inline_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
115 changes: 99 additions & 16 deletions app/services/audio_service.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,120 @@
# audio_service
# TODO: ugly code !!!!

import wave
import random
import struct
import uuid
import ffmpeg
import math

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():
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 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, 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(FREQ_LOW, FREQ_HIGH)
freq_channel_2 = random.randint(FREQ_LOW, FREQ_HIGH)
# duration of every chunk in seconds
chunk_duration = random.randint(1, 2)
# volume
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, 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()
# 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
Expand All @@ -44,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
Expand Down
26 changes: 16 additions & 10 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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()
Expand All @@ -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)

Expand Down
18 changes: 14 additions & 4 deletions tests/audio_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 7811563

Please sign in to comment.