Skip to content

Commit

Permalink
introduce accel and gryo sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
terryzfeng committed Oct 28, 2024
1 parent 9ee5eaf commit 227bd21
Show file tree
Hide file tree
Showing 13 changed files with 341 additions and 23 deletions.
19 changes: 17 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -328,18 +328,33 @@
<div id="inputPanelHeader" class="header h-7 justify-start flex-none drop-shadow-sm">
<button id="GUITab" type="button" class="header-item">GUI</button>
<button id="HIDTab" type="button" class="header-item">HID</button>
<button id="SensorTab" type="button" class="header-item">SENSOR</button>
</div>
<div id="GUIContainer" class="dark:bg-dark-2 w-full h-full">
<div id="GUIPanel" class="w-full h-full relative overflow-hidden">
</div>
</div>
<div id="HIDContainer" class="relative dark:bg-dark-2 w-full h-full overflow-auto md:overflow-hidden">
<div id="HIDPanel" class="absolute w-full h-full">
<div id="HIDPanel" class="absolute w-full h-full p-2">
<button id="mouseHIDButton" class="toggle-button w-32" disabled>Mouse: Off</button>
<button id="keyboardHIDButton" class="toggle-button w-32" disabled>Keyboard: Off</button>
<div id="hidLog" class="opacity-50 text-sm"></div>
<div id="hidLog" class="log-container opacity-50 text-sm"></div>
</div>
</div>
<div id="SensorContainer" class="relative dark:bg-dark-2 w-full h-full overflow-auto md:overflow-hidden">
<div id="SensorPanel" class="absolute w-full h-full p-2 pt-1">
<div class="pb-2 font-bold text-md">Mobile Only</div>
<div class="flex flex-wrap pb-1">
<button id="gyroButton" class="toggle-button w-32 mr-2" disabled>Gryo: Off</button>
<div id="gyroLog" class="log-container sensorLog opacity-50 text-sm"></div>
</div>
<div class="flex flex-wrap pb-1">
<button id="accelButton" class="toggle-button w-32 mr-2" disabled>Accel: Off</button>
<div id="accelLog" class="log-container sensorLog opacity-50 text-sm"></div>
</div>
</div>
</div>

</div>
</div>

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions public/examples/accelDemo.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
// name: accelDemo.ck
// desc: Accel-erometer WebChucK Demo (mobile only)
// Use mobile accelerometer to control sound synthesis
// NOTE: enable accelerometer in sensor settings
//
// Accel WebChucK Docs:
// https://chuck.stanford.edu/webchuck/docs/classes/Accel.html
//
// author: Mike Mulshine
//------------------------------------------------------------------------------

Accel ac;
AccelMsg msg;

0 => int device;

// open accel
if( !ac.openAccel( device ) ) me.exit();
<<< "accel '" + ac.name() + "' ready", "" >>>;

<<< "only on mobile" >>>;

SinOsc osc => Envelope gain => dac;
Noise noise => LPF filter => gain;

100 => float rootOscFreq;
rootOscFreq => osc.freq;

500 => float rootFilterFreq;
rootFilterFreq => filter.freq;

0.5 => filter.gain;

10::ms => gain.duration;
1.0 => gain.target;

// infinite event loop
while( true )
{
// wait on accel event
ac => now;

// get one or more messages
while( ac.recv( msg ) )
{
// print accel values
<<< msg.getAccelX() + " " + msg.getAccelY() + " " + msg.getAccelZ() >>>;
// compute average acceleration
(Math.fabs(msg.getAccelX()) +
Math.fabs(msg.getAccelY()) +
Math.fabs(msg.getAccelZ())) * 0.3333 => float avgAccel;

// control synthesis/filter freq
avgAccel * 10.0 => float dFreq;
rootOscFreq + dFreq => osc.freq;
rootFilterFreq + dFreq * 2.0 => filter.freq;
// control gain
avgAccel / 150.0 => float newGain;
newGain => gain.target;
}

10::ms => now;
}
60 changes: 60 additions & 0 deletions public/examples/gyro/gyroDemo.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
// name: gyroDemo.ck
// desc: Gyro-scope WebChucK Demo (mobile only)
// Use mobile gyroscope to control audio playback
// NOTE: enable gyroscope in sensor settings
//
// Gyro WebChucK Docs:
// https://chuck.stanford.edu/webchuck/docs/classes/Gyro.html
//
// author: Mike Mulshine
//------------------------------------------------------------------------------

Gyro gy;
GyroMsg msg;

0 => int device;

// open gyro
if( !gy.openGyro( device ) ) me.exit();
<<< "gyro '" + gy.name() + "' ready", "" >>>;

<<< "only on mobile" >>>;

SndBuf buf => Envelope gain => dac;
buf.read("gyroloop.wav");
0 => buf.pos;
1 => buf.loop;

10::ms => gain.duration;
1.0 => gain.target;

function float clamp(float val, float min, float max) {
if (val < min) return min;
if (val > max) return max;
return val;
}

// infinite event loop
while( true )
{
// wait on gyro event
gy => now;

// get one or more messages
while( gy.recv( msg ) )
{
// print gyro values
<<< msg.getGyroX() + " " + msg.getGyroY() + " " + msg.getGyroZ() >>>;

// normalize Y/Z gyro values to 0.0 to 1.0
Math.fabs(clamp(msg.getGyroY(), -90, 90)) / 90.0 => float gY;
(clamp(msg.getGyroZ(), -90, 90) + 90.0) / 180.0 => float gZ;

// control playback rate and envelope
gY => gain.target;
gZ * 2.0 => buf.rate;
}

10::ms => now;
}
Binary file added public/examples/gyro/gyroLoop.wav
Binary file not shown.
22 changes: 22 additions & 0 deletions src/components/examples/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,28 @@ export default class Examples {
() => loadChuckFileFromURL("examples/keyboardHID.ck"),
hidNested
);

// Sensor Nested Examples
const sensorNested = NestedDropdown.createNewNestedDropdown(
this.examplesDropdownContainer,
"sensor",
"Sensor"
);
Examples.newExample(
"Gyro Demo",
() => {
loadChuckFileFromURL("examples/gyro/gyroDemo.ck");
loadDataFileFromURL("examples/gyro/gyroLoop.wav");
},
sensorNested
);
Examples.newExample(
"Accel Demo",
() => {
loadChuckFileFromURL("examples/accelDemo.ck");
},
sensorNested
);
}

/**
Expand Down
8 changes: 6 additions & 2 deletions src/components/fileExplorer/projectSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ export default class ProjectSystem {
"Enter new file name",
"untitled.ck"
);
if (filename === "" || !filename) {
if (filename === null || filename === "") {
return;
}
if (ProjectSystem.projectFiles.has(filename)) {
Console.print(`${filename} already exists`);
return;
}
filename = filename.endsWith(".ck") ? filename : filename + ".ck";
Expand Down Expand Up @@ -180,7 +184,7 @@ export default class ProjectSystem {
} else {
if (wasActive) {
ProjectSystem.setActiveFile(
ProjectSystem.projectFiles.values().next().value
ProjectSystem.projectFiles.values().next().value!
);
}
}
Expand Down
25 changes: 22 additions & 3 deletions src/components/inputPanel/hidPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ const hidLog = document.querySelector<HTMLDivElement>("#hidLog")!;

export default class HidPanel {
public static hidMonitor: InputMonitor;
public static mouseActive: boolean = false;
public static keyboardActive: boolean = false;
constructor(hid: HID) {
// Create Hid Log
HidPanel.hidMonitor = new InputMonitor(hidLog, MAX_ELEMENTS, false);

// Mouse
new ButtonToggle(
mouseButton,
true,
Expand All @@ -26,16 +32,21 @@ export default class HidPanel {
document.addEventListener("mouseup", logMouseClick);
document.addEventListener("mousemove", logMouseMoveEvent);
document.addEventListener("wheel", logWheelEvent);
HidPanel.mouseActive = true;
HidPanel.setMonitorState();
},
() => {
hid.disableMouse();
document.removeEventListener("mousedown", logMouseClick);
document.removeEventListener("mouseup", logMouseClick);
document.removeEventListener("mousemove", logMouseMoveEvent);
document.removeEventListener("wheel", logWheelEvent);
HidPanel.mouseActive = false;
HidPanel.setMonitorState();
}
);

// Keyboard
new ButtonToggle(
keyboardButton,
true,
Expand All @@ -45,20 +56,28 @@ export default class HidPanel {
hid.enableKeyboard();
document.addEventListener("keydown", logKeyEvent);
document.addEventListener("keyup", logKeyEvent);
HidPanel.keyboardActive = true;
HidPanel.setMonitorState();
},
() => {
hid.disableKeyboard;
document.removeEventListener("keydown", logKeyEvent);
document.removeEventListener("keyup", logKeyEvent);
HidPanel.keyboardActive = false;
HidPanel.setMonitorState();
}
);

mouseButton.disabled = false;
keyboardButton.disabled = false;
HidPanel.mouseActive = true;
HidPanel.keyboardActive = true;
}

// Setup Hid Log
HidPanel.hidMonitor = new InputMonitor(hidLog, MAX_ELEMENTS);
hidLog.style.opacity = "100";
static setMonitorState() {
HidPanel.hidMonitor.setActive(
HidPanel.mouseActive || HidPanel.keyboardActive
);
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/components/inputPanel/inputMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
export default class InputMonitor {
public monitor: HTMLDivElement;
public max_elements: number;
public active: boolean;

constructor(div: HTMLDivElement, max_elements: number = 5) {
constructor(div: HTMLDivElement, max_elements: number = 5, active = false) {
this.monitor = div;
this.max_elements = max_elements;
this.active = active;
}

/**
Expand All @@ -39,4 +41,9 @@ export default class InputMonitor {
logEntry.classList.add("fade-out");
}, 1500);
}

setActive(active: boolean) {
this.monitor.style.opacity = active ? "1" : "0.5";
this.active = active;
}
}
9 changes: 9 additions & 0 deletions src/components/inputPanel/inputPanelHeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class InputPanelHeader {
InputPanelHeader.inputContainers.push(
document.querySelector<HTMLDivElement>("#GUIContainer")!
);

// HID
InputPanelHeader.inputButtons.push(
document.querySelector<HTMLButtonElement>("#HIDTab")!
Expand All @@ -26,6 +27,14 @@ export default class InputPanelHeader {
document.querySelector<HTMLDivElement>("#HIDContainer")!
);

// HID
InputPanelHeader.inputButtons.push(
document.querySelector<HTMLButtonElement>("#SensorTab")!
);
InputPanelHeader.inputContainers.push(
document.querySelector<HTMLDivElement>("#SensorContainer")!
);

// Build toggles with containers
for (let i = 0; i < InputPanelHeader.inputButtons.length; i++) {
InputPanelHeader.inputToggles.push(
Expand Down
Loading

0 comments on commit 227bd21

Please sign in to comment.