make sample rate configurable (#6)
Some checks failed
Python package / build-ubuntu (cp310-manylinux_x86_64, 3.10, /opt/python/cp310-cp310/include/python3.10, /opt/python/cp310-cp310/lib) (push) Has been cancelled
Python package / build-ubuntu (cp311-manylinux_x86_64, 3.11, /opt/python/cp311-cp311/include/python3.11, /opt/python/cp311-cp311/lib) (push) Has been cancelled
Python package / build-ubuntu (cp312-manylinux_x86_64, 3.12, /opt/python/cp312-cp312/include/python3.12, /opt/python/cp312-cp312/lib) (push) Has been cancelled
Python package / build-ubuntu (cp313-manylinux_x86_64, 3.13, /opt/python/cp313-cp313/include/python3.13, /opt/python/cp313-cp313/lib) (push) Has been cancelled
Python package / build-ubuntu (cp39-manylinux_x86_64, 3.9, /opt/python/cp39-cp39/include/python3.9, /opt/python/cp39-cp39/lib) (push) Has been cancelled
Python package / build-macos (arm64, cp310-macosx_arm64, macos-14, 3.10) (push) Has been cancelled
Python package / build-macos (arm64, cp311-macosx_arm64, macos-14, 3.11) (push) Has been cancelled
Python package / build-macos (arm64, cp312-macosx_arm64, macos-14, 3.12) (push) Has been cancelled
Python package / build-macos (arm64, cp313-macosx_arm64, macos-14, 3.13) (push) Has been cancelled
Python package / build-macos (arm64, cp39-macosx_arm64, macos-14, 3.9) (push) Has been cancelled
Python package / build-macos (x86_64, cp310-macosx_x86_64, macos-13, 3.10) (push) Has been cancelled
Python package / build-macos (x86_64, cp311-macosx_x86_64, macos-13, 3.11) (push) Has been cancelled
Python package / build-macos (x86_64, cp312-macosx_x86_64, macos-13, 3.12) (push) Has been cancelled
Python package / build-macos (x86_64, cp313-macosx_x86_64, macos-13, 3.13) (push) Has been cancelled
Python package / build-macos (x86_64, cp39-macosx_x86_64, macos-13, 3.9) (push) Has been cancelled
Python package / build-windows (cp310*, windows-2022, 3.10) (push) Has been cancelled
Python package / build-windows (cp311*, windows-2022, 3.11) (push) Has been cancelled
Python package / build-windows (cp312*, windows-2022, 3.12) (push) Has been cancelled
Python package / build-windows (cp313*, windows-2022, 3.13) (push) Has been cancelled
Python package / build-windows (cp39*, windows-2022, 3.9) (push) Has been cancelled
Python package / build-ubuntu (cp310-manylinux_x86_64, 3.10, /opt/python/cp310-cp310/include/python3.10, /opt/python/cp310-cp310/lib) (release) Has been cancelled
Python package / build-ubuntu (cp311-manylinux_x86_64, 3.11, /opt/python/cp311-cp311/include/python3.11, /opt/python/cp311-cp311/lib) (release) Has been cancelled
Python package / build-ubuntu (cp312-manylinux_x86_64, 3.12, /opt/python/cp312-cp312/include/python3.12, /opt/python/cp312-cp312/lib) (release) Has been cancelled
Python package / build-ubuntu (cp313-manylinux_x86_64, 3.13, /opt/python/cp313-cp313/include/python3.13, /opt/python/cp313-cp313/lib) (release) Has been cancelled
Python package / build-ubuntu (cp39-manylinux_x86_64, 3.9, /opt/python/cp39-cp39/include/python3.9, /opt/python/cp39-cp39/lib) (release) Has been cancelled
Python package / build-macos (arm64, cp310-macosx_arm64, macos-14, 3.10) (release) Has been cancelled
Python package / build-macos (arm64, cp311-macosx_arm64, macos-14, 3.11) (release) Has been cancelled
Python package / build-macos (arm64, cp312-macosx_arm64, macos-14, 3.12) (release) Has been cancelled
Python package / build-macos (arm64, cp313-macosx_arm64, macos-14, 3.13) (release) Has been cancelled
Python package / build-macos (arm64, cp39-macosx_arm64, macos-14, 3.9) (release) Has been cancelled
Python package / build-macos (x86_64, cp310-macosx_x86_64, macos-13, 3.10) (release) Has been cancelled
Python package / build-macos (x86_64, cp311-macosx_x86_64, macos-13, 3.11) (release) Has been cancelled
Python package / build-macos (x86_64, cp312-macosx_x86_64, macos-13, 3.12) (release) Has been cancelled
Python package / build-macos (x86_64, cp313-macosx_x86_64, macos-13, 3.13) (release) Has been cancelled
Python package / build-macos (x86_64, cp39-macosx_x86_64, macos-13, 3.9) (release) Has been cancelled
Python package / build-windows (cp310*, windows-2022, 3.10) (release) Has been cancelled
Python package / build-windows (cp311*, windows-2022, 3.11) (release) Has been cancelled
Python package / build-windows (cp312*, windows-2022, 3.12) (release) Has been cancelled
Python package / build-windows (cp313*, windows-2022, 3.13) (release) Has been cancelled
Python package / build-windows (cp39*, windows-2022, 3.9) (release) Has been cancelled
Python package / Upload wheels to PyPI (push) Has been cancelled
Python package / Upload wheels to PyPI (release) Has been cancelled

This commit is contained in:
Haokun Tian 2025-09-10 20:56:21 +01:00 committed by GitHub
parent bc6763a4e0
commit 6795bce6d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 24 additions and 16 deletions

View file

@ -1,6 +1,8 @@
PYTHONINCLUDEPATH := $(shell python3.10 -c "import sysconfig; print(sysconfig.get_path('include'))") PYTHON := $(shell which python)
PYTHONLIBPATH := $(shell python3.10 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") PYTHONINCLUDEPATH := $(shell $(PYTHON) -c "import sysconfig; print(sysconfig.get_path('include'))")
PYTHONLIBPATH := $(shell $(PYTHON) -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
ifndef CONFIG ifndef CONFIG
CONFIG=Release CONFIG=Release
@ -8,7 +10,7 @@ endif
ifndef LIBDIR ifndef LIBDIR
# LIBDIR=/usr/lib/ # LIBDIR=/usr/lib/
LIBDIR=$(shell python3.10 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") LIBDIR=$(shell $(PYTHON) -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
endif endif
BUILD_DATE="$(shell date +'%Y %m %d %H %M')" BUILD_DATE="$(shell date +'%Y %m %d %H %M')"

View file

@ -16,8 +16,7 @@ pip install vita
from scipy.io import wavfile from scipy.io import wavfile
import vita import vita
SAMPLE_RATE = 44_100 sample_rate = 44100
bpm = 120.0 bpm = 120.0
note_dur = 1.0 note_dur = 1.0
render_dur = 3.0 render_dur = 3.0
@ -27,6 +26,7 @@ velocity = 0.7 # [0.0 to 1.0]
synth = vita.Synth() synth = vita.Synth()
# The initial preset is loaded by default. # The initial preset is loaded by default.
synth.set_sample_rate(sample_rate)
synth.set_bpm(bpm) synth.set_bpm(bpm)
# Let's make a custom modulation using # Let's make a custom modulation using
@ -57,7 +57,7 @@ print(f"Current: {synth.get_control_text('delay_style')}") # e.g., "Stereo"
# Render audio to numpy array shaped (2, NUM_SAMPLES) # Render audio to numpy array shaped (2, NUM_SAMPLES)
audio = synth.render(pitch, velocity, note_dur, render_dur) audio = synth.render(pitch, velocity, note_dur, render_dur)
wavfile.write("generated_preset.wav", SAMPLE_RATE, audio.T) wavfile.write("generated_preset.wav", sample_rate, audio.T)
# Dump current state to JSON text # Dump current state to JSON text
preset_path = "generated_preset.vital" preset_path = "generated_preset.vital"

View file

@ -448,8 +448,13 @@ void SynthBase::pySetBPM(float bpm) {
engine_->setBpm(bpm); engine_->setBpm(bpm);
}; };
// src/plugin/synth_plugin.cpp Line 129-133 prepareToPlay
void SynthBase::setSampleRate(double sample_rate) {
engine_->setSampleRate(sample_rate);
midi_manager_->setSampleRate(sample_rate);
}
void SynthBase::renderAudioToFile(File file, std::vector<int> notes, float velocity, float note_dur, float render_dur, bool render_images) { void SynthBase::renderAudioToFile(File file, std::vector<int> notes, float velocity, float note_dur, float render_dur, bool render_images) {
static constexpr int kSampleRate = 44100;
static constexpr int kPreProcessSamples = 44100; static constexpr int kPreProcessSamples = 44100;
static constexpr int kFadeSamples = 200; static constexpr int kFadeSamples = 200;
static constexpr int kBufferSize = 64; static constexpr int kBufferSize = 64;
@ -464,11 +469,11 @@ void SynthBase::renderAudioToFile(File file, std::vector<int> notes, float veloc
engine_->allSoundsOff(); // note: dbraun added this engine_->allSoundsOff(); // note: dbraun added this
processModulationChanges(); processModulationChanges();
engine_->setSampleRate(kSampleRate);
// engine_->setBpm(bpm); // engine_->setBpm(bpm);
engine_->updateAllModulationSwitches(); engine_->updateAllModulationSwitches();
int kSampleRate = getSampleRate();
double sample_time = 1.0 / getSampleRate(); double sample_time = 1.0 / kSampleRate;
double current_time = -kPreProcessSamples * sample_time; double current_time = -kPreProcessSamples * sample_time;
for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) { for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) {
@ -575,7 +580,6 @@ void SynthBase::renderAudioToFile(File file, std::vector<int> notes, float veloc
} }
nb::ndarray<float, nb::shape<2, -1>, nb::numpy> SynthBase::renderAudioToNumpy(const int& midi_note, float velocity, float note_dur, float render_dur) { nb::ndarray<float, nb::shape<2, -1>, nb::numpy> SynthBase::renderAudioToNumpy(const int& midi_note, float velocity, float note_dur, float render_dur) {
static constexpr int kSampleRate = 44100;
static constexpr int kFadeSamples = 200; static constexpr int kFadeSamples = 200;
static constexpr int kBufferSize = 64; static constexpr int kBufferSize = 64;
static constexpr int kPreProcessSamples = 256; // note: dbraun decreased this from 44100. static constexpr int kPreProcessSamples = 256; // note: dbraun decreased this from 44100.
@ -588,11 +592,11 @@ nb::ndarray<float, nb::shape<2, -1>, nb::numpy> SynthBase::renderAudioToNumpy(co
engine_->allSoundsOff(); // note: dbraun added this engine_->allSoundsOff(); // note: dbraun added this
processModulationChanges(); processModulationChanges();
engine_->setSampleRate(kSampleRate);
engine_->updateAllModulationSwitches(); engine_->updateAllModulationSwitches();
int kSampleRate = getSampleRate();
// Preprocess modulation // Preprocess modulation
double sample_time = 1.0 / getSampleRate(); double sample_time = 1.0 / kSampleRate;
double current_time = -kPreProcessSamples * sample_time; double current_time = -kPreProcessSamples * sample_time;
for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) { for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) {

View file

@ -139,6 +139,7 @@ class SynthBase : public MidiManager::Listener {
Tuning* getTuning() { return &tuning_; } Tuning* getTuning() { return &tuning_; }
void pySetBPM(float bpm); void pySetBPM(float bpm);
void setSampleRate(double sample_rate);
struct ValueChangedCallback : public CallbackMessage { struct ValueChangedCallback : public CallbackMessage {
ValueChangedCallback(std::shared_ptr<SynthBase*> listener, std::string name, vital::mono_float val) : ValueChangedCallback(std::shared_ptr<SynthBase*> listener, std::string name, vital::mono_float val) :

View file

@ -572,6 +572,7 @@ NB_MODULE(vita, m) {
"Disconnects a modulation source from a destination by name.") "Disconnects a modulation source from a destination by name.")
.def("set_bpm", &HeadlessSynth::pySetBPM, nb::arg("bpm")) .def("set_bpm", &HeadlessSynth::pySetBPM, nb::arg("bpm"))
.def("set_sample_rate", &HeadlessSynth::setSampleRate, nb::arg("sample_rate"))
.def("render_file", &HeadlessSynth::renderAudioToFile2, .def("render_file", &HeadlessSynth::renderAudioToFile2,
nb::arg("output_path"), nb::arg("midi_note"), nb::arg("output_path"), nb::arg("midi_note"),

View file

@ -20,15 +20,14 @@ from vita.constants import (
SyncedFrequency, SyncedFrequency,
) )
SAMPLE_RATE = 44_100
def test_render(bpm=120.0, sample_rate=48000, note_dur=1.0, render_dur=3.0, pitch=36, velocity=0.7):
def test_render(bpm=120.0, note_dur=1.0, render_dur=3.0, pitch=36, velocity=0.7):
synth = vita.Synth() synth = vita.Synth()
# The initial preset is laoded by default. # The initial preset is laoded by default.
synth.set_bpm(bpm) synth.set_bpm(bpm)
synth.set_sample_rate(sample_rate)
assert vita.get_modulation_sources() assert vita.get_modulation_sources()
assert vita.get_modulation_destinations() assert vita.get_modulation_destinations()
@ -43,8 +42,9 @@ def test_render(bpm=120.0, note_dur=1.0, render_dur=3.0, pitch=36, velocity=0.7)
# Render audio to numpy array shaped (2, NUM_SAMPLES) # Render audio to numpy array shaped (2, NUM_SAMPLES)
audio = synth.render(pitch, velocity, note_dur, render_dur) audio = synth.render(pitch, velocity, note_dur, render_dur)
assert sample_rate == int(audio.shape[1] / render_dur) # assume int
wavfile.write("generated_preset.wav", SAMPLE_RATE, audio.T) wavfile.write("generated_preset.wav", sample_rate, audio.T)
# Dump current state to json text # Dump current state to json text
json_text = synth.to_json() json_text = synth.to_json()