mirror of
https://github.com/archr-linux/Arch-R.git
synced 2026-03-31 14:41:55 -07:00
Merge pull request #2286 from beebono/ds-features
Add hardware microphone support to drastic-sa and fix melonds-sa DirectBoot priority
This commit is contained in:
@@ -60,7 +60,7 @@ controls_a[CONTROL_INDEX_SWAP_ORIENTATION_A] = 65535
|
||||
controls_a[CONTROL_INDEX_SWAP_ORIENTATION_B] = 65535
|
||||
controls_a[CONTROL_INDEX_LOAD_GAME] = 65535
|
||||
controls_a[CONTROL_INDEX_QUIT] = 65535
|
||||
controls_a[CONTROL_INDEX_FAKE_MICROPHONE] = 65535
|
||||
controls_a[CONTROL_INDEX_FAKE_MICROPHONE] = 327
|
||||
controls_a[CONTROL_INDEX_UI_UP] = 1217
|
||||
controls_a[CONTROL_INDEX_UI_DOWN] = 1153
|
||||
controls_a[CONTROL_INDEX_UI_LEFT] = 1216
|
||||
@@ -98,7 +98,7 @@ controls_b[CONTROL_INDEX_SWAP_ORIENTATION_A] = 65535
|
||||
controls_b[CONTROL_INDEX_SWAP_ORIENTATION_B] = 65535
|
||||
controls_b[CONTROL_INDEX_LOAD_GAME] = 65535
|
||||
controls_b[CONTROL_INDEX_QUIT] = 65535
|
||||
controls_b[CONTROL_INDEX_FAKE_MICROPHONE] = 65535
|
||||
controls_b[CONTROL_INDEX_FAKE_MICROPHONE] = 327
|
||||
controls_b[CONTROL_INDEX_UI_UP] = 1037
|
||||
controls_b[CONTROL_INDEX_UI_DOWN] = 1038
|
||||
controls_b[CONTROL_INDEX_UI_LEFT] = 1039
|
||||
|
||||
@@ -31,6 +31,9 @@ makeinstall_target() {
|
||||
cp -rf ${PKG_BUILD}/drastic_aarch64/* ${INSTALL}/usr/config/drastic/
|
||||
cp -rf ${PKG_DIR}/config/${DEVICE}/* ${INSTALL}/usr/config/drastic/config/
|
||||
cp -rf ${PKG_DIR}/config/drastic.gptk ${INSTALL}/usr/config/drastic/
|
||||
|
||||
mkdir -p ${INSTALL}/usr/config/drastic/microphone
|
||||
cp -f ${PKG_DIR}/sources/microphone.wav ${INSTALL}/usr/config/drastic/microphone/
|
||||
}
|
||||
|
||||
post_install() {
|
||||
|
||||
@@ -16,6 +16,7 @@ PLATFORM="nds"
|
||||
HIRES3D=$(get_setting hires_3d "${PLATFORM}" "${GAME}")
|
||||
THREADED3D=$(get_setting threaded_3d "${PLATFORM}" "${GAME}")
|
||||
FOLLOW3D=$(get_setting follow_3d_renderer "${PLATFORM}" "${GAME}")
|
||||
MICTHRESH=$(get_setting microphone_sensitivity "${PLATFORM}" "${GAME}")
|
||||
|
||||
#load gptokeyb support files
|
||||
control-gen_init.sh
|
||||
@@ -92,12 +93,9 @@ if [ "${HW_DEVICE}" = "S922X" ]; then
|
||||
fi
|
||||
|
||||
$GPTOKEYB "drastic" -c "drastic.gptk" &
|
||||
# Fix actual touch inputs by replacing touch->mouse translation
|
||||
# Fix actual touch inputs by replacing touch->mouse translation and add hw mic support
|
||||
export LD_PRELOAD="/usr/lib/libdrastouch.so"
|
||||
export SDL_TOUCH_MOUSE_EVENTS="0"
|
||||
export DSHOOK_MIC_THRESH="${MICTHRESH}"
|
||||
./drastic "$1"
|
||||
kill -9 $(pidof gptokeyb)
|
||||
|
||||
if echo "${UI_SERVICE}" | grep "sway"; then
|
||||
kill -9 $(pidof drastic_sense.sh)
|
||||
fi
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#include <dlfcn.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
static int ds_screen_width = 256;
|
||||
static int ds_screen_height = 192;
|
||||
@@ -14,6 +17,14 @@ static int logical_width = -1;
|
||||
static int logical_height = -1;
|
||||
static int actual_touch = 0;
|
||||
|
||||
// Microphone monitoring
|
||||
static SDL_AudioDeviceID mic_device = 0;
|
||||
static int mic_key_held = 0;
|
||||
static float mic_threshold = 0.0f;
|
||||
static int mic_enabled = 0;
|
||||
static float mic_baseline = 0.0f;
|
||||
static int mic_baseline_samples = 0;
|
||||
|
||||
static SDL_Texture* screens[4];
|
||||
static SDL_Texture* stylus_tex[2];
|
||||
static SDL_Rect touch_rect_storage = {0};
|
||||
@@ -26,6 +37,14 @@ static int (*real_SDL_RenderSetLogicalSize)(SDL_Renderer*, int, int) = NULL;
|
||||
static SDL_Texture* (*real_SDL_CreateTexture)(SDL_Renderer*, Uint32, int, int, int) = NULL;
|
||||
static int (*real_SDL_RenderCopy)(SDL_Renderer*, SDL_Texture*, const SDL_Rect*, const SDL_Rect*) = NULL;
|
||||
static int (*real_SDL_PollEvent)(SDL_Event*) = NULL;
|
||||
static int (*real_SDL_PushEvent)(SDL_Event*) = NULL;
|
||||
static Uint32 (*real_SDL_WasInit)(Uint32) = NULL;
|
||||
static int (*real_SDL_InitSubSystem)(Uint32) = NULL;
|
||||
static SDL_AudioDeviceID (*real_SDL_OpenAudioDevice)(const char*, int, const SDL_AudioSpec*, SDL_AudioSpec*, int) = NULL;
|
||||
static void (*real_SDL_PauseAudioDevice)(SDL_AudioDeviceID, int) = NULL;
|
||||
static void (*real_SDL_CloseAudioDevice)(SDL_AudioDeviceID) = NULL;
|
||||
static int (*real_SDL_GetNumAudioDevices)(int) = NULL;
|
||||
static const char* (*real_SDL_GetAudioDeviceName)(int, int) = NULL;
|
||||
|
||||
SDL_Window* SDL_CreateWindow(const char* title, int x, int y, int w, int h, Uint32 flags) {
|
||||
int num_displays = SDL_GetNumVideoDisplays();
|
||||
@@ -156,6 +175,53 @@ int SDL_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
|
||||
return real_SDL_RenderCopy(renderer, texture, srcrect, dstrect);
|
||||
}
|
||||
|
||||
void mic_audio_callback(void* userdata, Uint8* stream, int len) {
|
||||
if (!mic_enabled) return;
|
||||
|
||||
Sint16* samples = (Sint16*)stream;
|
||||
int sample_count = len / 2;
|
||||
|
||||
// Calculate RMS amplitude
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < sample_count; i++) {
|
||||
float sample = samples[i] / 32768.0f; // Normalize to [-1.0..1.0]
|
||||
sum += sample * sample;
|
||||
}
|
||||
float rms = sqrtf(sum / sample_count);
|
||||
|
||||
// Build ambient baseline over first ~3 seconds
|
||||
if (mic_baseline_samples < 60) {
|
||||
mic_baseline = (mic_baseline * mic_baseline_samples + rms) / (mic_baseline_samples + 1);
|
||||
mic_baseline_samples++;
|
||||
return; // Don't trigger during calibration
|
||||
}
|
||||
|
||||
mic_baseline = mic_baseline * 0.999f + rms * 0.001f;
|
||||
|
||||
// Trigger only if significantly above baseline
|
||||
float trigger_level = mic_baseline + mic_threshold;
|
||||
int should_hold = (rms > trigger_level);
|
||||
if (should_hold && !mic_key_held) {
|
||||
// Noise detected, press Scroll Lock
|
||||
SDL_Event key_event = {0};
|
||||
key_event.type = SDL_KEYDOWN;
|
||||
key_event.key.state = SDL_PRESSED;
|
||||
key_event.key.keysym.scancode = SDL_SCANCODE_SCROLLLOCK;
|
||||
key_event.key.keysym.sym = SDLK_SCROLLLOCK;
|
||||
real_SDL_PushEvent(&key_event);
|
||||
mic_key_held = 1;
|
||||
} else if (!should_hold && mic_key_held) {
|
||||
// Noise dropped below threshold, release Scroll Lock
|
||||
SDL_Event key_event = {0};
|
||||
key_event.type = SDL_KEYUP;
|
||||
key_event.key.state = SDL_RELEASED;
|
||||
key_event.key.keysym.scancode = SDL_SCANCODE_SCROLLLOCK;
|
||||
key_event.key.keysym.sym = SDLK_SCROLLLOCK;
|
||||
real_SDL_PushEvent(&key_event);
|
||||
mic_key_held = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int SDL_PollEvent(SDL_Event* event) {
|
||||
// Loop required to filter events we don't want to pass along
|
||||
while (1) {
|
||||
@@ -188,7 +254,7 @@ int SDL_PollEvent(SDL_Event* event) {
|
||||
event->button.state = SDL_PRESSED;
|
||||
event->button.x = x;
|
||||
event->button.y = y;
|
||||
SDL_PushEvent(event);
|
||||
real_SDL_PushEvent(event);
|
||||
|
||||
// Jump to new position
|
||||
event->type = SDL_MOUSEMOTION;
|
||||
@@ -253,6 +319,60 @@ static void init(void) {
|
||||
real_SDL_CreateTexture = dlsym(RTLD_NEXT, "SDL_CreateTexture");
|
||||
real_SDL_RenderCopy = dlsym(RTLD_NEXT, "SDL_RenderCopy");
|
||||
real_SDL_PollEvent = dlsym(RTLD_NEXT, "SDL_PollEvent");
|
||||
real_SDL_PushEvent = dlsym(RTLD_NEXT, "SDL_PushEvent");
|
||||
real_SDL_WasInit = dlsym(RTLD_NEXT, "SDL_WasInit");
|
||||
real_SDL_InitSubSystem = dlsym(RTLD_NEXT, "SDL_InitSubSystem");
|
||||
real_SDL_OpenAudioDevice = dlsym(RTLD_NEXT, "SDL_OpenAudioDevice");
|
||||
real_SDL_PauseAudioDevice = dlsym(RTLD_NEXT, "SDL_PauseAudioDevice");
|
||||
real_SDL_CloseAudioDevice = dlsym(RTLD_NEXT, "SDL_CloseAudioDevice");
|
||||
real_SDL_GetNumAudioDevices = dlsym(RTLD_NEXT, "SDL_GetNumAudioDevices");
|
||||
real_SDL_GetAudioDeviceName = dlsym(RTLD_NEXT, "SDL_GetAudioDeviceName");
|
||||
|
||||
const char* threshold_str = getenv("DSHOOK_MIC_THRESH");
|
||||
if (threshold_str) {
|
||||
mic_threshold = atof(threshold_str);
|
||||
if (mic_threshold > 0.0f) {
|
||||
mic_enabled = 1;
|
||||
|
||||
// Make sure SDL audio is ready, just in case
|
||||
if (real_SDL_WasInit(SDL_INIT_AUDIO) == 0)
|
||||
real_SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
|
||||
int num_devices = real_SDL_GetNumAudioDevices(1);
|
||||
const char* device_name = NULL;
|
||||
for (int i = 0; i < num_devices; i++) {
|
||||
const char* name = real_SDL_GetAudioDeviceName(i, 1);
|
||||
// Use first available device (or look for Built-in)
|
||||
if (name && (i == 0 || strstr(name, "Built-in"))) {
|
||||
device_name = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure audio capture
|
||||
SDL_AudioSpec desired_spec = {0};
|
||||
desired_spec.freq = 44100;
|
||||
desired_spec.format = AUDIO_S16SYS;
|
||||
desired_spec.channels = 1;
|
||||
desired_spec.samples = 2048;
|
||||
desired_spec.callback = mic_audio_callback;
|
||||
|
||||
SDL_AudioSpec obtained_spec;
|
||||
mic_device = real_SDL_OpenAudioDevice(device_name, 1, &desired_spec, &obtained_spec, 0);
|
||||
|
||||
if (mic_device > 0) // Opened, start capture
|
||||
real_SDL_PauseAudioDevice(mic_device, 0);
|
||||
else // Couldn't open, fallback to disable
|
||||
mic_enabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((destructor))
|
||||
static void cleanup(void) {
|
||||
if (mic_device > 0 && real_SDL_CloseAudioDevice) {
|
||||
real_SDL_CloseAudioDevice(mic_device);
|
||||
}
|
||||
}
|
||||
|
||||
// Major thanks/credit to Shaun Inman for providing the basis of this hook library!
|
||||
Binary file not shown.
@@ -68,12 +68,12 @@ fi
|
||||
if [ "$PLATFORM" = "ndsiware" ]; then
|
||||
sed -i '/^DirectBoot=/c\DirectBoot=0' /storage/.config/melonDS/melonDS.ini
|
||||
else
|
||||
if [ "$DBOOT" = "1" ]; then
|
||||
sed -i '/^DirectBoot=/c\DirectBoot=1' /storage/.config/melonDS/melonDS.ini
|
||||
sed -i '/^ExternalBIOSEnable=/c\ExternalBIOSEnable=0' /storage/.config/melonDS/melonDS.ini
|
||||
else
|
||||
if [ "$DBOOT" = "0" ]; then
|
||||
sed -i '/^DirectBoot=/c\DirectBoot=0' /storage/.config/melonDS/melonDS.ini
|
||||
sed -i '/^ExternalBIOSEnable=/c\ExternalBIOSEnable=1' /storage/.config/melonDS/melonDS.ini
|
||||
else
|
||||
sed -i '/^DirectBoot=/c\DirectBoot=1' /storage/.config/melonDS/melonDS.ini
|
||||
sed -i '/^ExternalBIOSEnable=/c\ExternalBIOSEnable=0' /storage/.config/melonDS/melonDS.ini
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@ if [ ! -d "/storage/.config/drastic" ]; then
|
||||
mkdir -p "/storage/.config/drastic"
|
||||
cp -r "/usr/config/drastic" "/storage/.config/"
|
||||
fi
|
||||
if [ -f "/storage/.config/drastic/config/drastic.cfg.rgds" ]; then
|
||||
cp /storage/.config/drastic/config/drastic.cfg.rgds /storage/.config/drastic/config/drastic.cfg
|
||||
if [ -f "/storage/.config/drastic/config/drastic.cfg.rgds" ] && [ -f "/storage/.config/drastic/config/drastic.cfg" ]; then
|
||||
sed -i '/^controls_b/d' /storage/.config/drastic/config/drastic.cfg
|
||||
grep '^controls_b' /storage/.config/drastic/config/drastic.cfg.rgds >> /storage/.config/drastic/config/drastic.cfg
|
||||
elif [ -f "/storage/.config/drastic/config/drastic.cfg.rgds" ]; then
|
||||
# Fall back to full copy if user drastic.cfg doesn't exist for some reason
|
||||
cp /storage/.config/drastic/config/drastic.cfg.rgds /storage/.config/drastic/config/drastic.cfg
|
||||
fi
|
||||
|
||||
@@ -1624,6 +1624,12 @@
|
||||
<choice name="on" value="1" />
|
||||
<choice name="off" value= "0" />
|
||||
</feature>
|
||||
<feature name="microphone sensitivity">
|
||||
<choice name="off" value="0" />
|
||||
<choice name="high" value="0.03" />
|
||||
<choice name="medium" value="0.15" />
|
||||
<choice name="low" value="0.3" />
|
||||
</feature>
|
||||
</features>
|
||||
</core>
|
||||
</cores>
|
||||
|
||||
Reference in New Issue
Block a user