Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gamepad module #1223

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
93 changes: 93 additions & 0 deletions packages/gamepad/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# @strudel/gamepad

This package adds gamepad input functionality to strudel Patterns.

## Install

```sh
npm i @strudel/gamepad --save
```

## Usage

```javascript
import { gamepad } from '@strudel/gamepad';

// Initialize gamepad (optional index parameter, defaults to 0)
const pad = gamepad(0);

// Use gamepad inputs in patterns
const pattern = sequence([
// Button inputs
pad.a, // A button value (0-1)
pad.tglA, // A button toggle (0 or 1)

// Analog stick inputs
pad.x1, // Left stick X (0-1)
pad.x1_2, // Left stick X (-1 to 1)
]);
```

## Available Controls

### Buttons
- Face Buttons
- `a`, `b`, `x`, `y` (or uppercase `A`, `B`, `X`, `Y`)
- Toggle versions: `tglA`, `tglB`, `tglX`, `tglY`
- Shoulder Buttons
- `lb`, `rb`, `lt`, `rt` (or uppercase `LB`, `RB`, `LT`, `RT`)
- Toggle versions: `tglLB`, `tglRB`, `tglLT`, `tglRT`
- D-Pad
- `up`, `down`, `left`, `right` (or `u`, `d`, `l`, `r` or uppercase)
- Toggle versions: `tglUp`, `tglDown`, `tglLeft`, `tglRight`(or `tglU`, `tglD`, `tglL`, `tglR`)

### Analog Sticks
- Left Stick
- `x1`, `y1` (0 to 1 range)
- `x1_2`, `y1_2` (-1 to 1 range)
- Right Stick
- `x2`, `y2` (0 to 1 range)
- `x2_2`, `y2_2` (-1 to 1 range)

## Examples

```javascript
// Use button values to control amplitude
$: sequence([
s("bd").gain(pad.X), // X button controls gain
s("[hh oh]").gain(pad.tglY), // Y button toggles gain
]);

// Use analog stick for continuous control
$: note("c4*4".add(pad.y1_2.range(-24,24))) // Left stick Y controls pitch shift
.pan(pad.x1_2); // Left stick X controls panning

// Use toggle buttons to switch patterns on/off

// Define button sequences
const HADOKEN = [
'd', // Down
'r', // Right
'a', // A
];

const KONAMI = 'uuddlrlrba' //Konami Code ↑↑↓↓←→←→BA

// Add these lines to enable buttons(but why?)
$:pad.D.segment(16).gain(0)
$:pad.R.segment(16).gain(0)
$:pad.A.segment(16).gain(0)

// Check button sequence (returns 1 when detected, 0 when not within last 1 second)
$: sound("hadoken").gain(pad.checkSequence(HADOKEN))

```

## Multiple Gamepads

You can connect multiple gamepads by specifying the gamepad index:

```javascript
const pad1 = gamepad(0); // First gamepad
const pad2 = gamepad(1); // Second gamepad
```
117 changes: 117 additions & 0 deletions packages/gamepad/docs/gamepad.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { MiniRepl } from '../../../website/src/docs/MiniRepl';

# Gamepad

The Gamepad module allows you to integrate gamepad input functionality into your musical patterns. This can be particularly useful for live performances or interactive installations where you want to manipulate sounds using a game controller.

## Getting Started

Initialize a gamepad by calling the gamepad() function with an optional index parameter.

<MiniRepl
client:idle
tune={`// Initialize gamepad (optional index parameter, defaults to 0)
const gp = gamepad(0)
note("c a f e").mask(gp.a)`}
/>

## Available Controls

The gamepad module provides access to buttons and analog sticks as normalized signals (0-1) that can modulate your patterns.

### Buttons

| Type | Controls |
| ---------------- | ---------------------------------------------------------------------------------------------- |
| Face Buttons | `a`, `b`, `x`, `y` (or uppercase `A`, `B`, `X`, `Y`) |
| | Toggle versions: `tglA`, `tglB`, `tglX`, `tglY` |
| Shoulder Buttons | `lb`, `rb`, `lt`, `rt` (or uppercase `LB`, `RB`, `LT`, `RT`) |
| | Toggle versions: `tglLB`, `tglRB`, `tglLT`, `tglRT` |
| D-Pad | `up`, `down`, `left`, `right` (or `u`, `d`, `l`, `r` or uppercase) |
| | Toggle versions: `tglUp`, `tglDown`, `tglLeft`, `tglRight` (or `tglU`, `tglD`, `tglL`, `tglR`) |

### Analog Sticks

| Stick | Controls |
| ----------- | ------------------------------ |
| Left Stick | `x1`, `y1` (0 to 1 range) |
| | `x1_2`, `y1_2` (-1 to 1 range) |
| Right Stick | `x2`, `y2` (0 to 1 range) |
| | `x2_2`, `y2_2` (-1 to 1 range) |

### Button Sequence

| Stick | Controls |
| --------------- | --------------------------------------- |
| Button Sequence | `btnSequence()`, `btnSeq()`, `btnseq()` |

## Using Gamepad Inputs

Once initialized, you can use various gamepad inputs in your patterns. Here are some examples:

### Button Inputs

You can use button inputs to control different aspects of your music, such as gain or triggering events.

<MiniRepl
client:idle
tune={`const gp = gamepad(0)
// Use button values to control amplitude
$: stack(
s("[[hh hh] oh hh oh]/2").mask(gp.tglX).bank("RolandTR909"), // X btn for HH
s("cr*1").mask(gp.Y).bank("RolandTR909"), // LB btn for CR
s("bd").mask(gp.tglA).bank("RolandTR909"), // A btn for BD
s("[ht - - mt - - lt - ]/2").mask(gp.tglB).bank("RolandTR909"), // B btn for Toms
s("sd*4").mask(gp.RB).bank("RolandTR909"), // RB btn for SD
).cpm(120)
`}
/>

### Analog Stick Inputs

Analog sticks can be used for continuous control, such as pitch shifting or panning.

<MiniRepl
client:idle
tune={`const gp = gamepad(0)
// Use analog stick for continuous control
$: note("c4 d3 a3 e3").sound("sawtooth")
.lpf(gp.x1.range(100,4000))
.lpq(gp.y1.range(5,30))
.decay(gp.y2.range(0.1,2))
.lpenv(gp.x2.range(-5,5))
.cpm(120)
`}
/>

### Button Sequences

You can define button sequences to trigger specific actions, like playing a sound when a sequence is detected.

<MiniRepl client:idle tune={`const gp = gamepad(0)
// Define button sequences
const HADOUKEN = [
'd', // Down
'r', // Right
'a', // A
]
const KONAMI = 'uuddlrlrba' //Konami Code ↑↑↓↓←→←→BA

// Check butto-n sequence (returns 1 while detected, 0 when not within last 1 second)
$: s("free_hadouken -").slow(2)
.mask(gp.btnSequence(HADOUKEN)).room(1).cpm(120)

// hadouken.wav by Syna-Max
//https://freesound.org/people/Syna-Max/sounds/67674/
samples({free_hadouken: 'https://cdn.freesound.org/previews/67/67674_111920-lq.mp3'})
`} />

## Multiple Gamepads

Strudel supports multiple gamepads. You can specify the gamepad index to connect to different devices.

<MiniRepl
client:idle
tune={`const pad1 = gamepad(0); // First gamepad
const pad2 = gamepad(1); // Second gamepad`}
/>
Loading