diff --git a/public/audio-processor.js b/public/audio-processor.js new file mode 100644 index 0000000..f7f07b4 --- /dev/null +++ b/public/audio-processor.js @@ -0,0 +1,40 @@ +class AudioProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.desiredBufferSize = 20*1024; // 期望的缓冲区大小 + this.buffer = new Float32Array(this.desiredBufferSize); + this.bufferIndex = 0; + } + + process(inputs, outputs, parameters) { + const input = inputs[0]; + const channel = input[0]; + + if (channel && channel.length > 0) { + // 将新数据添加到缓冲区 + for (let i = 0; i < channel.length; i++) { + this.buffer[this.bufferIndex++] = channel[i]; + + // 当缓冲区满时,发送数据 + if (this.bufferIndex >= this.desiredBufferSize) { + // 将浮点音频数据转换为16位整数 + const pcmData = new Int16Array(this.desiredBufferSize); + for (let j = 0; j < this.desiredBufferSize; j++) { + pcmData[j] = Math.min(Math.max(this.buffer[j] * 32767, -32767), 32767); + } + + // 发送数据到主线程 + this.port.postMessage(pcmData.buffer, [pcmData.buffer]); + + // 重置缓冲区 + this.buffer = new Float32Array(this.desiredBufferSize); + this.bufferIndex = 0; + } + } + } + + return true; + } +} + +registerProcessor('audio-processor', AudioProcessor); \ No newline at end of file diff --git a/src/assets/js/GamepadController.js b/src/assets/js/GamepadController.js index 942f5e4..d283ad2 100644 --- a/src/assets/js/GamepadController.js +++ b/src/assets/js/GamepadController.js @@ -1,84 +1,137 @@ class GamepadController { - constructor(config = {}) { - this.config = { - buttonMapping: {}, - axisMapping: {}, - ...config + constructor(options = {}) { + this.options = { + ...{ + debug: false, + deadZone: 0.1, + updateInterval: 50, + buttonsConfig: [ + { name: "Left2", index: 6 }, + { name: "Back", index: 8 }, + { name: "Right Joystick Press", index: 11 } + ] + }, + ...options }; + + this.gamepadIndex = null; this.gamepad = null; - this.listeners = {}; + this.interval = null; + this.buttons = []; + this.directionAxis0_1 = ""; + this.directionAxis9 = ""; + this.angle = 0; + // 初始化按钮状态 + this.buttons = this.options.buttonsConfig.map(button => ({ + ...button, + pressed: false + })); - // 初始化默认按键映射 - Object.assign(this.config.buttonMapping, { - 0: 'A', - 1: 'B', - 2: 'X', - 3: 'Y', - // 其他默认映射 - }); + // 注册事件监听器 + window.addEventListener("gamepadconnected", this.onGamepadConnected.bind(this)); + window.addEventListener("gamepaddisconnected", this.onGamepadDisconnected.bind(this)); - // 初始化默认摇杆映射 - Object.assign(this.config.axisMapping, { - 0: 'leftX', - 1: 'leftY', - 2: 'rightX', - 3: 'rightY', - // 其他默认映射 - }); + if (this.options.debug) { + console.log("GamepadController initialized with options:", this.options); + } } - connect() { - window.addEventListener('gamepadconnected', (e) => { - this.gamepad = navigator.getGamepads()[e.gamepad.index]; - this.triggerEvent('connected'); - }); + onGamepadConnected(e) { + console.log("Gamepad connected:", e.gamepad); + this.gamepadIndex = e.gamepad.index; + this.gamepad = navigator.getGamepads()[this.gamepadIndex]; + this.startGamepad(); } - disconnect() { - window.removeEventListener('gamepadconnected', this.handleConnect); + onGamepadDisconnected() { + clearInterval(this.interval); this.gamepad = null; - this.triggerEvent('disconnected'); + if (this.options.debug) { + console.log("Gamepad disconnected"); + } } - // 手动获取手柄数据的方法 - pollGamepad() { - if (!this.gamepad) return; - - // 处理摇杆数据 - const axesData = this.gamepad.axes; - const axisEvents = {}; - Object.entries(this.config.axisMapping).forEach(([index, name]) => { - axisEvents[name] = axesData[index]; - }); - this.triggerEvent('axisChange', axisEvents); - - // 处理按键事件 - const buttons = this.gamepad.buttons; - buttons.forEach((btn, index) => { - if (btn.value === 1 && this.config.buttonMapping[index]) { - const keyName = this.config.buttonMapping[index]; - this.triggerEvent('buttonPress', { keyName, index }); + startGamepad() { + this.interval = setInterval(() => { + const gamepads = navigator.getGamepads(); + const gamepad = gamepads[this.gamepadIndex]; + + if (gamepad) { + // 注释掉调试打印 + // if (this.options.debug) { + // console.log('Axes data:', { + // axis0: gamepad.axes[0], + // axis1: gamepad.axes[1], + // gamepadIndex: this.gamepadIndex + // }); + // } + + this.updateDirection(gamepad.axes); + this.updateDirectionAxis9(gamepad.axes); + this.pressKey(gamepad.buttons); } + }, this.options.updateInterval); + } + + updateDirection(axes) { + const axis0 = axes[0]; + const axis1 = axes[1]; + + // 检查是否在死区 + if (Math.abs(axis0) < this.options.deadZone && Math.abs(axis1) < this.options.deadZone) { + this.directionAxis0_1 = "未定义"; + this.angle = 0; // 在死区时重置角度为0 + return; + } + + // 计算方向角度(0-360度) + let angle = Math.atan2(axis1, axis0) * (180 / Math.PI); + angle = (angle + 360) % 360; // 确保角度在 0-360 范围内 + angle = Math.round(angle); + this.angle = angle; + + // 更新方向数据 + if (Math.abs(axis0) > this.options.deadZone || Math.abs(axis1) > this.options.deadZone) { + this.directionAxis0_1 = `${angle}°`; + // 注释掉调试打印 + // if (this.options.debug) { + // console.log(` 摇杆方向: ${angle}°, X轴: ${axis0.toFixed(2)}, Y轴: ${axis1.toFixed(2)}`); + // } + } + } + + updateDirectionAxis9(axes) { + const axis9 = axes[9]; + const roundedAxis9 = Math.round(axis9 * 100) / 100; + if (roundedAxis9 <= -0.9) { + this.directionAxis9 = "上"; + } else if (roundedAxis9 >= 0.0 && roundedAxis9 <= 0.2) { + this.directionAxis9 = "下"; + } else if (roundedAxis9 >= 0.6 && roundedAxis9 <= 0.8) { + this.directionAxis9 = "左"; + } else if (roundedAxis9 >= -0.5 && roundedAxis9 <= -0.4) { + this.directionAxis9 = "右"; + } else { + this.directionAxis9 = "未定义"; + } + } + + pressKey(buttons) { + this.buttons.forEach(button => { + const buttonData = buttons[button.index]; + button.pressed = buttonData ? buttonData.value === 1 : false; }); } - addEventListener(type, callback) { - if (!this.listeners[type]) this.listeners[type] = []; - this.listeners[type].push(callback); - } - - triggerEvent(type, data = {}) { - if (this.listeners[type]) { - this.listeners[type].forEach(callback => callback(data)); + destroy() { + clearInterval(this.interval); + window.removeEventListener("gamepadconnected", this.onGamepadConnected); + window.removeEventListener("gamepaddisconnected", this.onGamepadDisconnected); + if (this.options.debug) { + console.log("GamepadController destroyed"); } } } -// 导出模块 -if (typeof module !== 'undefined' && module.exports) { - module.exports = GamepadController; -} else if (typeof define === 'function' && define.amd) { - define([], () => GamepadController); -} else { - window.GamepadController = GamepadController; -} \ No newline at end of file +// 导出类以便外部使用 +export default GamepadController; \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 7efe543..58945eb 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,7 +1,7 @@ import { createRouter, createWebHashHistory } from 'vue-router'; import { useStore } from 'vuex'; import Home from '../views/home/home.vue'; -import CarControl from '../views/CarControl.vue'; // 导入小车控制页面 +import CarControl from '../views/CarControl.vue'; // 直接导入组件 const routes = [ { @@ -48,9 +48,9 @@ const routes = [ component: () => import('../views/voice/voiceset.vue') }, { - path: '/car_control', // 添加小车控制的路由 + path: '/car_control', name: 'CarControl', - component: () => import('../views/CarControl.vue') + component: CarControl, // 直接使用导入的组件,而不是使用动态导入 }, { path: '/audio-play', diff --git a/src/views/AudioPlay.vue b/src/views/AudioPlay.vue index a034644..c447bb6 100644 --- a/src/views/AudioPlay.vue +++ b/src/views/AudioPlay.vue @@ -5,6 +5,31 @@ {{ isRecording ? '停止传输音频' : '开始传输音频' }}
{{ status }}
+