From 75b42e876b177dff22da33b9c9486b99aeee87ae Mon Sep 17 00:00:00 2001 From: dafteran4 <72914975+dafteran4@users.noreply.github.com> Date: Sat, 14 Feb 2026 18:32:14 +0100 Subject: [PATCH] Noise for haptics (#31) --- conf/monocoque.config | 1 + .../devices/sound/usb_generic_shaker_pulse.c | 59 +++++++++++++++---- src/monocoque/devices/sounddevice.c | 2 + src/monocoque/devices/sounddevice.h | 1 + src/monocoque/helper/confighelper.c | 2 + src/monocoque/helper/confighelper.h | 1 + 6 files changed, 53 insertions(+), 13 deletions(-) diff --git a/conf/monocoque.config b/conf/monocoque.config index f533b1e..da7f716 100644 --- a/conf/monocoque.config +++ b/conf/monocoque.config @@ -26,6 +26,7 @@ configs = ( modulation = "frequency"; frequency = 17; frequencyMax = 37; + noise = 10; // additive noise in Hz }, { device = "Sound"; diff --git a/src/monocoque/devices/sound/usb_generic_shaker_pulse.c b/src/monocoque/devices/sound/usb_generic_shaker_pulse.c index 74ac8aa..9097fa4 100644 --- a/src/monocoque/devices/sound/usb_generic_shaker_pulse.c +++ b/src/monocoque/devices/sound/usb_generic_shaker_pulse.c @@ -16,6 +16,15 @@ #define M_PI (3.14159265) #endif +static double apply_noise(double base_freq, double noise_amount) { + if (noise_amount > 0.0) { + double r = (double) rand() / RAND_MAX * 2.0 - 1.0; + return base_freq + r * noise_amount; + } else { + return base_freq; + } +} + void gear_sound_stream(pa_stream *s, size_t length, void *userdata) { SoundData* data = (SoundData*)userdata; @@ -24,21 +33,44 @@ void gear_sound_stream(pa_stream *s, size_t length, void *userdata) { for (size_t i = 0; i < num_samples; i++) { - static double t = 0.0; - double sample = 0; - if (data->frequency>0) - { - sample = ((double)data->curr_amplitude/100) * 32767.0 * sin(2.0 * M_PI * data->curr_frequency * data->curr_duration); - } + double sample = 0; + + if (data->curr_frequency>0.0) + { + double t = data->phase; + double a = (double)data->curr_amplitude/100; + + // fade-out 5ms to prevent discontinuity + static double fade_out_duration = 0.005; + + double remaining = data->duration - data->curr_duration; + if (remaining < fade_out_duration) { + a *= remaining / fade_out_duration; + } + + sample = a * 32767.0 * sin(2.0 * M_PI * t); + + double f = apply_noise(data->curr_frequency, data->noise); + + t += f / SAMPLE_RATE; + if (t >= 1.0) { + t -= floor(t); + } + + data->phase = t; + + data->curr_duration += 1.0 / SAMPLE_RATE; + if (data->curr_duration >= data->duration) { + data->curr_duration = 0.0; + data->curr_frequency = 0.0; + data->phase = 0.0; + } + + } buffer[i] = (int16_t)sample; - data->curr_duration += 1.0 / SAMPLE_RATE; - if (data->curr_duration >= data->duration) { - data->curr_duration = 0.0; - data->curr_frequency = 0.0; - } } pa_stream_write(s, buffer, length, NULL, 0LL, PA_SEEK_RELATIVE); } @@ -46,7 +78,6 @@ void gear_sound_stream(pa_stream *s, size_t length, void *userdata) { void engine_sound_stream(pa_stream *s, size_t length, void *userdata) { SoundData* data = (SoundData*)userdata; - double freq = data->curr_frequency; size_t num_samples = length / sizeof(int16_t); @@ -62,7 +93,9 @@ void engine_sound_stream(pa_stream *s, size_t length, void *userdata) { buffer[i] = (int16_t)sample; - t += freq / SAMPLE_RATE; + double f = apply_noise(data->curr_frequency, data->noise); + + t += f / SAMPLE_RATE; if (t >= 1.0) { t -= floor(t); } diff --git a/src/monocoque/devices/sounddevice.c b/src/monocoque/devices/sounddevice.c index 3a1420f..e123f07 100644 --- a/src/monocoque/devices/sounddevice.c +++ b/src/monocoque/devices/sounddevice.c @@ -177,6 +177,7 @@ int sounddev_init(SoundDevice* sounddevice, const char* devname, MonocoqueTyreId slogi("pan is: %i", sds.pan); slogi("channels is: %i", sds.channels); slogi("duration is: %f", sds.duration); + slogi("noise is: %i", sds.noise); sounddevice->modulationType = sds.modulation; @@ -184,6 +185,7 @@ int sounddev_init(SoundDevice* sounddevice, const char* devname, MonocoqueTyreId sounddevice->sounddata.frequencyMax = sds.frequencyMax; sounddevice->sounddata.amplitude = sds.amplitude; sounddevice->sounddata.amplitudeMax = sds.amplitudeMax; + sounddevice->sounddata.noise = (double)sds.noise; sounddevice->sounddata.curr_duration = 0; sounddevice->sounddata.phase = 0; diff --git a/src/monocoque/devices/sounddevice.h b/src/monocoque/devices/sounddevice.h index 1690895..33824c4 100644 --- a/src/monocoque/devices/sounddevice.h +++ b/src/monocoque/devices/sounddevice.h @@ -30,6 +30,7 @@ typedef struct uint32_t curr_amplitude; double curr_duration; double phase; + double noise; } SoundData; diff --git a/src/monocoque/helper/confighelper.c b/src/monocoque/helper/confighelper.c index 3891040..b25e86a 100644 --- a/src/monocoque/helper/confighelper.c +++ b/src/monocoque/helper/confighelper.c @@ -747,6 +747,7 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co ds->sounddevsettings.pan = 0; ds->sounddevsettings.channels = 1; ds->sounddevsettings.duration = 2.0; + ds->sounddevsettings.noise = 0; if (ds->effect_type == EFFECT_GEARSHIFT) { ds->sounddevsettings.duration = .125; @@ -762,6 +763,7 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co config_setting_lookup_int(device_settings, "pan", &ds->sounddevsettings.pan); config_setting_lookup_int(device_settings, "channels", &ds->sounddevsettings.channels); config_setting_lookup_float(device_settings, "duration", &ds->sounddevsettings.duration); + config_setting_lookup_int(device_settings, "noise", &ds->sounddevsettings.noise); const char* temp = NULL; int found = 0; diff --git a/src/monocoque/helper/confighelper.h b/src/monocoque/helper/confighelper.h index 4555b79..f9792df 100644 --- a/src/monocoque/helper/confighelper.h +++ b/src/monocoque/helper/confighelper.h @@ -185,6 +185,7 @@ typedef struct double duration; char* dev; SoundEffectModulationType modulation; + int noise; } SoundDeviceSettings;