Initial Commit

Volkor 2022-11-17 15:56:07 +11:00
commit 159a721ff0
Signed by: Volkor
5 changed files with 125 additions and 0 deletions

.gitignore vendored Normal file
View File

@ -0,0 +1 @@

36 Normal file
View File

@ -0,0 +1,36 @@
# VolkorSoundBoard (VSB)
VSB is a cool python-based, OSC-enabled vrchat soundboard.
It uses a avatars radial menu to trigger .wav files to play via a audio device, mostly voicemeeter.
## Software setup
0. Ensure python 3.10 (or older!!) is installed, and you have the requirements installed. `pip install -r requirements.txt`
1. In the SFX folder, create a folder for the avatarid, for example `avtr_3ec08725-aa6c-42ec-b411-a1466f69fb61`, and then move the audio files in.
2. Ensure that the files are named properly, with proper numbering at the start of the filename.
3. Ensure that the files are in WAV format. I don't think the sound library supports playing anything else (and I haven't added it working)
4. Edit the config.toml to match your settings.
## Avatar setup
1. Create a submenu with the corresponding `osc-parameter` settings triggered by a button.
1. TODO: add a photo or something to show my example
2. Enable OSC in game (or test with [AV3Emulator!](
3. Upload avatar (or play mode if AV3Emu) and run the button, and see if it is registered in the program.
## Python 3.11 or newer
We use the tomli library for toml, but python 3.11 and newer has tomllib built into python, so you'll have to change the import and references.
## Stuff I learned making this
- How OSC works! (osc4py3 is neat, especially multithreading stuff)
- signals library for clean ctrl+c exiting
- playing audio on windows from python (sounddevice, soundfile)
- reading toml files from python.
## File naming
Files MUST be named correctly. `1. <name>`.
The number in the filename corresponds to the number in the parameter menu in VRC.
Files MUST be in .wav format. Seriously. I'm not requiring ffmpeg for a small size reduction.

config.toml Normal file
View File

@ -0,0 +1,13 @@
# Change me to talk to a different pc (although idk how you're piping audio to another pc but nice)
ip = ""
port = 9001
# Sets the default playback device, use `python -m sounddevice` to list all devices, and select the one you want by setting below. Moron.
# You'd want to find the VoiceMeeter (MME) ones.
# You can also use a name for this, it'll match text.
audio-device = "VoiceMeeter Aux Input (VB-Audio"
osc-parameter = "OSC-VoiceLine"

72 Normal file
View File

@ -0,0 +1,72 @@
import time
from osc4py3.as_comthreads import *
from osc4py3 import oscmethod as osm
import sounddevice as sd
import soundfile as sf
import glob
from pathlib import Path
import tomli
import signal
## 1. set up persistence and have different folders for different avid's
## will need to listen for '/avatar/change' messages, adding that into the play_voiceline thing.
# Setup config stuffs
with open("config.toml", mode="rb") as fp:
config = tomli.load(fp)
osc_parameter = "/avatar/parameters/" + config["vrchat"]["osc-parameter"]
sd.default.device = config["audio"]["audio-device"]
def get_voiceline_path(VoiceLine):
# Returns the FIRST result from finding "<number>."
print(f"[VSB] Searching for file: {VoiceLine}")
# Calculates the file to search for.
search_path = Path('./SFX')/ f'{VoiceLine}.*.wav'
print(f"[VSB] Searching for path: {search_path}")
# Do the search and save the output
file = glob.glob(str(search_path))
return file[0]
def play_voiceline(VoiceLine, VoiceLinePath):
# Load selected file into ram. (I imagine this will be GC'd at some point)
print(f"[VSB] Loading Voiceline: ({VoiceLine}) {VoiceLinePath}")
data, samplerate =, samplerate)
print(f"[VSB] Playing Voiceline: ({VoiceLine}) {VoiceLinePath}")
sd.wait() # This forces the program to wait until playback is finished!!!
print(f"[VSB] Finished Voiceline: ({VoiceLine}) {VoiceLinePath}")
# Only called when voiceline detected.
def main(VoiceLine):
print(f"[VSB] Received message: {VoiceLine}")
VoiceLinePath = get_voiceline_path(VoiceLine)
play_voiceline(VoiceLine, VoiceLinePath)
# Startup the server (this is a function because im shit at coding)
def init_osc():
osc_udp_server(config["networking"]["ip"], config["networking"]["port"], "VolkorSoundBoard")
osc_method(osc_parameter, main)
def exit_handler(signum, frame):
print(f"[VSB] Exiting, thanks for flying VSB Airlines!")
# Start the system.
print(f"[VSB] Initializing...")
signal.signal(signal.SIGINT, exit_handler)
# Periodically call osc4py3 processing method in your event loop.
finished = False
slep = 0
killtime = 100
while not finished:
time.sleep(0.1) # Stops it from using 10% cpu on my 5800x (delays processing by ~50ms)
slep = slep + 1

requirements.txt Normal file
View File

@ -0,0 +1,3 @@