Describe patterns and the piano roll #333
- New page Patterns: the asset, the tab, drawing and editing, keys, the ruler with loop and start, playing through the scheduler. - Instruments, Architecture, Keyboard, Home, Concepts and the sidebar point to it. Development counts module 64. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent
ea30223538
commit
0610d7a352
8 files changed
+126
-12
No files matched your search
+8
-2
@@ -148,7 +148,8 @@ src/core/time.ts the global clock: one scaled step a frame, shared by the
|
||||
src/core/music/ time (ticks, 480 to the quarter, tempo and meter, a position as bar, beat and tick), sequence
|
||||
(the notes of a window of playing time, across the seam of a loop — a pure rule), Scheduler
|
||||
(#332: plans the notes ahead on the audio clock through a host, so it is measured with a clock
|
||||
of the test's own)
|
||||
of the test's own), pattern (#333: a pattern's notes, grid, meter, tempo and loop, held to
|
||||
their rules, and the sequence it plays)
|
||||
src/runtime/ GameRun (one run: start, tick, `Load scene` — shared by Play and a released game, #266),
|
||||
World, Entity, System interface, Input tracker, CollisionSystem (the editor run's detection),
|
||||
solids (what `Move` collides with and how it slides — one-way solids let it through unless
|
||||
@@ -206,7 +207,7 @@ src/viewport/ WorldViewport (the drawing of a world or a holder, the ba
|
||||
core/soundfx/pitchPlayer, a phase vocoder, #317; a note of an instrument is one voice
|
||||
of what reaches its Output, each way with its own file, #331; a voice can start and be released
|
||||
at a second of the audio clock, #332), music (the scheduler on the library's clock, its
|
||||
notes played by the project's instruments, driven by `__gm.music` until #333) + musicTimer
|
||||
notes played by the project's instruments: the Pattern tab's player, #333, and `__gm.music`) + musicTimer
|
||||
(the Web Worker whose interval is the scheduler's beat, #332), ShaderLibrary, ParticleLibrary,
|
||||
particles (one ParticleContainer per source), tilemap (one container per layer),
|
||||
shaderPicture (the picture a shader is laid over when it shades a camera's frame, #299, or
|
||||
@@ -337,6 +338,11 @@ src/editor/curve/ CurveEditor (header: Preset, the picked point's type, Pre
|
||||
graph drawn from curveValue, points and handles edited with the vector art gestures, the
|
||||
preview dot and its rail) + curveView (the curve laid onto a picture for those gestures and
|
||||
read back, a point held between its neighbours, a point put down on free space)
|
||||
src/editor/pattern/ PatternEditor (header: Play, Grid; plays through the scheduler and follows edits, #333),
|
||||
PianoRoll (keys, ruler, notes and velocity lane in one widget, the gestures and keys) +
|
||||
rollView (its geometry: rows, hits, bands) + rollEdit (what a gesture does to the notes)
|
||||
src/editor/music/ timeView (the time axis: ticks to pixels, zoom, the lines of bars, beats and grid) + TimeRuler
|
||||
(bars, loop, start and playhead) — for the piano roll and the song tab (#334)
|
||||
src/editor/tile/ TileEditor (header + kind), TileCanvas (every tile of the block and a sample map, animated),
|
||||
PictureStrip (the pictures as animation steps; its reorder maths is `dropIndex` in ui/sortable),
|
||||
TilePalette (the tiles as a grid of pictures in the tilemap panel, #139)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
| **Asset** | Named thing with a type (`scene`, `camera`, `clip`, `sprite`, `text`, `behavior`, `collider`, `container`, `texture`, `animation`, `statemachine`, `shader`, `shaderfunction`, `font`, `sound`, `soundfx`, `instrument`, `particles`, `variables`) and typed properties. Assets have **no position**. |
|
||||
| **Texture** | An uploaded image. Scenes, textures, animations, state machines, shaders, fonts, sounds and Variables assets are the eight types that cannot be placed: a texture has no position, it is *worn* by a sprite through the ordinary property `texture`. See [Textures](Textures). |
|
||||
| **Font** | An uploaded typeface, worn by a text through the ordinary property `font`; no font means the editor's own. Uploaded and picked exactly like a texture, and stored the same way. See [Fonts](Fonts). |
|
||||
| **Sound** | An uploaded audio file. Uploaded, picked and stored exactly like a typeface — but nothing *wears* it: it is neither on screen nor in the scene, and a graph plays it with `Play sound`. Its own rows say how loud it is and whether it loops; the node scales the one and can overrule the other either way. A **sound FX** asset is a graph of effects (gain, pitch, EQ, mix) a `Play sound` can send it through. See [Sounds](Sounds). An **instrument** plays sounds as notes, see [Instruments](Instruments). |
|
||||
| **Sound** | An uploaded audio file. Uploaded, picked and stored exactly like a typeface — but nothing *wears* it: it is neither on screen nor in the scene, and a graph plays it with `Play sound`. Its own rows say how loud it is and whether it loops; the node scales the one and can overrule the other either way. A **sound FX** asset is a graph of effects (gain, pitch, EQ, mix) a `Play sound` can send it through. See [Sounds](Sounds). An **instrument** plays sounds as notes, see [Instruments](Instruments), and a **pattern** is notes for one, drawn in a piano roll, see [Patterns](Patterns). |
|
||||
| **State machine** | A named set of **states**, edited as nodes in its own tab. A behavior puts it into a state with `Set state`, moves it along a named transition with `State transition` and branches on it with `State branch`. Its **Scope** says where the current state lives: **Local** gives every behavior instance one of its own, **Global** keeps a single one for the whole run. See [State machines](State-machines). |
|
||||
| **Shader** | A node graph that becomes the GLSL a sprite is drawn with, edited in its own tab. A sprite, a text or a particle source wears it through `shader`; the numbers the graph declares are rows below that dropdown. A **shader function** is a part of such a graph kept on its own and used as a node in other shaders. See [Shaders](Shaders). |
|
||||
| **Particles** | A node graph that says what *one* particle is as a function of its age and of a random number drawn once for it — no forces, no simulation. Unlike the other graph assets it **is** placeable: the object made from it is a source, whose rows say how many go out and for how long they live. Because a particle is a formula, the same second always draws the same picture and the tab's slider can jump to any of them exactly. See [Particles](Particles). |
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ php tests/php/accounts.test.php # the API's accoun
|
||||
# has and the web server's container has not (SKIP there)
|
||||
php tests/php/snapshots.test.php # the snapshot store (#231), the same way
|
||||
php tests/php/releases.test.php # the release store (#266), the same way
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1744 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1796 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
|
||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||
./e2e.sh status # live progress, or the last run's result
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ Live: <https://nockal.com/game-maker/> · Widget playground: <https://nockal.com
|
||||
| [Fonts](Fonts) | Uploading a typeface, what a text wears, what the editor falls back to |
|
||||
| [Sounds](Sounds) | Uploading a sound, what the asset says, `Play sound` and `Stop sound`, sound FX (gain, pitch, EQ, mix, delay) and how long a voice rings on, what a pause and a stop do to a voice |
|
||||
| [Instruments](Instruments) | The instrument asset: Notes, Sample, Parameters, Sound FX, Envelope and Output, triggers, zones and layers, the keys of the Instrument tab, `Play note` |
|
||||
| [Patterns](Patterns) | The pattern asset and its piano roll: drawing, moving and lengthening notes, the grid, the ruler with start and loop, velocities, playing it in a loop |
|
||||
| [Animations](Animations) | Animation assets, the Animation tab, how they run |
|
||||
| [Curves](Curves) | Easings drawn by hand, the Curve tab, using one on a key or a `Lerp` |
|
||||
| [Tiles](Tiles) | The tile asset, plain tiles and the two autotile kinds, the pictures as animation steps, the Tile tab |
|
||||
|
||||
+8
-7
@@ -1,10 +1,10 @@
|
||||
An **instrument** (**+ → Instrument**, #331) makes a note a sound. It is a node graph like a
|
||||
[sound FX](Sounds#sound-fx): **Notes** nodes bring the note in, a **Sample** plays a sound for it,
|
||||
the effects of a sound FX shape it and the **Output** is what is heard. It is the first piece of
|
||||
the music tools planned in #330: a pattern (#333) and a song (#334) will play instruments. Until
|
||||
then a behavior plays one with **Play note**, and the tab plays it from its keys.
|
||||
the music tools planned in #330: a [pattern](Patterns) (#333) plays one, and a song (#334) will.
|
||||
A behavior plays one with **Play note**, and the tab plays it from its keys.
|
||||
|
||||
Instruments are listed under **Music** in the asset panel, where patterns and songs will join them.
|
||||
Instruments are listed under **Instruments** in the asset panel, patterns under **Patterns**.
|
||||
A new one starts as *Notes* → *Sample* → *Output*: every note from C4 to B4 plays the Sample,
|
||||
which waits for its sound to be picked.
|
||||
|
||||
@@ -18,7 +18,7 @@ A at 440 Hz, 127 the highest. A note is named with its octave after it and no da
|
||||
|
||||
| Node | What it does |
|
||||
| --- | --- |
|
||||
| **Notes** | Where the notes come in. `any` triggers what it is connected to for every note from **From** to **To**. `note` is the number of the note played, `frequency` its pitch in Hz (`440 * 2^((note - 69) / 12)`), `velocity` how hard it is struck, 0 to 1. With **Single notes** there is one trigger output for every note in the range as well, and each can have a **name** of its own (*Name of C2* in the inspector): the output shows it, and a piano roll will. |
|
||||
| **Notes** | Where the notes come in. `any` triggers what it is connected to for every note from **From** to **To**. `note` is the number of the note played, `frequency` its pitch in Hz (`440 * 2^((note - 69) / 12)`), `velocity` how hard it is struck, 0 to 1. With **Single notes** there is one trigger output for every note in the range as well, and each can have a **name** of its own (*Name of C2* in the inspector): the output shows it, and so do the keys of the [piano roll](Patterns#the-pattern-tab). |
|
||||
| **Sample** | Plays a sound asset when its `trigger` is on. With **Follow note** (on by default) it plays higher or lower by the distance from **Root**, the note it sounds as it is (C4 by default), and **keeps its length** — it is played by the same worklet as a Pitch (#317). Off, every note plays it as it is, as for a drum. **Play** says how it is played while the note is held and once it is let go (table below). **Loop start** and **Loop end** are in seconds, 0 at the end being the end of the sound. The volume of the sound asset counts. |
|
||||
| **Parameters** | The instrument's own parameters, each a number output with a default — like the parameters of a sound FX's Input. One per instrument. |
|
||||
| **Sound FX** | Sends the sound through a sound FX asset, as if it were the sound at the FX's Input. Every parameter of that FX is an input here; one left open is the FX's default. The node is titled after the FX, and a double click opens it. |
|
||||
@@ -193,8 +193,9 @@ different instruments, `Play note` warns.
|
||||
## Playing in time
|
||||
|
||||
The **scheduler** (#332) plays notes of instruments in time, on the clock of the sound rather than
|
||||
the game's, so a slow frame or a busy page never moves a note. Patterns and songs (#333, #334) will
|
||||
be made of it; nothing in the editor plays a sequence yet, only the check scripts do (`__gm.music`).
|
||||
the game's, so a slow frame or a busy page never moves a note. The Pattern tab plays a
|
||||
[pattern](Patterns#playing) with it, a song (#334) will, and the check scripts drive it directly
|
||||
(`__gm.music`).
|
||||
|
||||
- **Ticks.** Musical time is counted in ticks, **480 to the quarter note** as in MIDI files: a
|
||||
1/32 triplet is 40, a 1/16 quintuplet 96, all whole numbers. The tempo always counts quarter
|
||||
@@ -226,6 +227,6 @@ be made of it; nothing in the editor plays a sequence yet, only the check script
|
||||
|
||||
## Not yet
|
||||
|
||||
No oscillators or 8-bit sources (#329), no patterns or songs (#333, #334), no swing. An Envelope
|
||||
No oscillators or 8-bit sources (#329), no songs (#334), no swing. An Envelope
|
||||
shapes notes of an instrument only, not a sound played through a sound FX. Notes can not be played from an `.mid` file or a MIDI
|
||||
keyboard.
|
||||
+1
-1
@@ -8,7 +8,7 @@ without it, before anything else those keys do ([Behaviors](Behaviors)) ·
|
||||
under the pointer ([Scene editing](Scene-editing), [Behaviors](Behaviors)) · `Ctrl+V` import an image from
|
||||
the clipboard as a texture when nothing copied fits the tab (ignored while a text field has focus) · Animation tab: `Ctrl+C` copy
|
||||
the picked keys, `Ctrl+V` paste them at the playhead (while keys are copied this takes `Ctrl+V`
|
||||
there, so an image is pasted from another tab), `Ctrl`+drag duplicate keys · `Tab` / `Shift+Tab` cycle fields (in the Game tab with no field focused, Tab is a game key like any other, and the key field of `On key down` takes it too) · lists: `↑`/`↓` move,
|
||||
there, so an image is pasted from another tab), `Ctrl`+drag duplicate keys · Pattern tab: `Space` play/stop, `Ctrl+C`/`Ctrl+V` copy the picked notes and paste them where playing starts, `Ctrl+D` duplicate them behind themselves, `Ctrl+A` pick all, `↑`/`↓` a semitone (`Shift` an octave), `←`/`→` a grid step (`Shift` a bar), `Alt` while drawing, moving or lengthening leaves the grid ([Patterns](Patterns#drawing-and-editing)) · `Tab` / `Shift+Tab` cycle fields (in the Game tab with no field focused, Tab is a game key like any other, and the key field of `On key down` takes it too) · lists: `↑`/`↓` move,
|
||||
`←`/`→` fold, `Enter` activates · number
|
||||
fields: drag to scrub (`Shift` x10, `Alt` x0.1, snapping to the grid of that increment, so a
|
||||
step-1 field lands on whole numbers), `↑`/`↓` step, shown with at most three decimals and without trailing zeros
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
A **pattern** (**+ → Pattern**, #333) is a stretch of notes for one [instrument](Instruments),
|
||||
drawn in a piano roll. It is the second piece of the music tools of #330: a song (#334) will lay
|
||||
patterns out on tracks, and several songs and tracks can use the same pattern.
|
||||
|
||||
Patterns are listed under **Patterns** in the asset panel, the instruments under **Instruments**.
|
||||
A new pattern is empty: four bars of 4/4 at 120 BPM, drawn on a 1/16 grid, with no instrument yet.
|
||||
|
||||
## What a pattern says
|
||||
|
||||
The notes and the loop are the pattern's own data; everything else is a row in the inspector.
|
||||
|
||||
| Row | What it does |
|
||||
|---|---|
|
||||
| **Instrument** | What plays the notes, and what the keys of the tab play. Without one the notes can be drawn, but nothing sounds. |
|
||||
| **Length (bars)** | 1 to 256 bars. A note starting at the end or behind it is kept, drawn faint, and not played; a note reaching past the end is cut off there. |
|
||||
| **Grid** | What a note is drawn and moved on: 1/1 to 1/32, and the triplets 1/4T to 1/32T. The tab's header has the same choice. |
|
||||
| **Beats per bar**, **Beat** | The meter, any one: 3/4, 6/8, 7/8. It only says where the bars and beats of the ruler are; the notes are kept in ticks, so a pattern changed from 4/4 to 6/8 keeps every note where it was. |
|
||||
| **Tempo (BPM)** | 20 to 400, quarter notes a minute, for hearing the pattern in its tab. A song will play it at its own tempo. |
|
||||
|
||||
A note is a start and a length in ticks (480 to the quarter note, see
|
||||
[Playing in time](Instruments#playing-in-time)), a note number (60 is C4) and a velocity from 0 to 1.
|
||||
One instrument plays the whole pattern; a drum kit is one instrument with a name per note (see
|
||||
*Single notes* on [Instruments](Instruments#the-nodes)).
|
||||
|
||||
## The Pattern tab
|
||||
|
||||
Down the left are the **keys**, the highest note on top. A key the instrument plays nothing for is
|
||||
grey, a note a drum kit has named shows its name, every C its note name. A key sounds while the
|
||||
pointer holds it. Along the top is the **ruler** with the bars numbered from 1 and the beats as
|
||||
short ticks, the loop as a band along its top edge and where playing starts as a small triangle at
|
||||
its foot. Between them are the **notes**, each a bar in its key's row, the brighter the harder it is
|
||||
struck; picked notes are light with a white edge. Below them is the **velocity lane**: a stem at
|
||||
the start of every note, as high as its velocity.
|
||||
|
||||
The header has **Play** (it turns into **Stop**), the **Grid**, **Fit** and on the right the number
|
||||
of notes and the instrument. **Fit** shows the whole pattern across and its notes (or, with none,
|
||||
what the instrument plays) down the middle.
|
||||
|
||||
### Drawing and editing
|
||||
|
||||
| Do this | And this happens |
|
||||
|---|---|
|
||||
| Click into the grid | A note at the grid line before the pointer, as long as the last note drawn or lengthened (a grid step at first), with the last velocity set (0.8 at first). It is picked and sounds for a moment. |
|
||||
| Drag a note by its body | It moves along the grid and to the key under the pointer, the other picked notes with it. It sounds again on every new key. |
|
||||
| Drag a note by its right end | It takes the length to the grid line nearest the pointer, the other picked notes lengthen by as much. |
|
||||
| Hold `Alt` while drawing, moving or lengthening | Off the grid, on the tick. A note is at least one tick long. |
|
||||
| Drag on empty grid | A band; the notes it touches are picked. With `Shift` they are added to the pick. |
|
||||
| `Shift`-click a note | Adds it to the pick or takes it out. |
|
||||
| Right-click a note | Deletes it; dragging on with the right button deletes every note it passes. |
|
||||
| Drag a stem in the velocity lane | Sets that note's velocity; if the note is picked, the other picked notes move by as much. |
|
||||
|
||||
Every drag is one undo step, and so is every key below that changes notes.
|
||||
|
||||
| Key (the roll focused) | |
|
||||
|---|---|
|
||||
| `Space` | Play or stop. |
|
||||
| `Delete`, `Backspace` | Delete the picked notes. With none picked the key does nothing, so a second press never asks about the pattern itself. |
|
||||
| `Ctrl+C`, `Ctrl+V` | Copy the picked notes; paste them so the earliest lands where playing starts. The copy works for every pattern of the project. |
|
||||
| `Ctrl+D` | A copy of the picked notes right behind them, moved by whole grid steps, picked in their place. |
|
||||
| `Ctrl+A` | Pick every note. |
|
||||
| `↑` / `↓` | The picked notes a semitone up or down, with `Shift` an octave. |
|
||||
| `←` / `→` | The picked notes a grid step earlier or later, with `Shift` a bar. |
|
||||
| `Esc` | Pick nothing. |
|
||||
|
||||
`Ctrl+C`, `Ctrl+V` and `Delete` work on the tab also when the keyboard is somewhere else in the
|
||||
editor, the way they do in the other tabs.
|
||||
|
||||
### The ruler
|
||||
|
||||
- A **click** sets where playing starts (on the grid line before it, with `Alt` on the tick). A
|
||||
paste lands there. While the pattern plays, it jumps there.
|
||||
- A **drag** spans the loop, on the grid. Near an end of the loop a drag moves that end.
|
||||
- A **right-click** offers *Loop bar N* and *Loop the whole pattern*. With no loop set the whole
|
||||
pattern is the loop, and a shorter pattern cuts a loop at its end.
|
||||
|
||||
### Zoom and scroll
|
||||
|
||||
The wheel scrolls up and down, with `Shift` across (a trackpad scrolls both ways). The wheel on
|
||||
the ruler, or with `Alt` anywhere but the keys, zooms the time about the pointer; with `Alt` on the
|
||||
keys it zooms the rows. A middle-drag pans both ways. `Ctrl`+wheel is left to the browser, which
|
||||
zooms the page with it. Only what is on screen is drawn, so a pattern of some hundred notes stays
|
||||
quick.
|
||||
|
||||
## Playing
|
||||
|
||||
**Space** or **Play** plays the pattern round its loop from where playing starts, through the
|
||||
scheduler (#332): each note is planned ahead on the clock of the sound and starts on its sample.
|
||||
A playhead runs over the grid, the lane and the ruler. An edit while it plays is heard from the
|
||||
next window on, without starting over: a note drawn ahead of the playhead in this round, one drawn
|
||||
behind it in the next. A new loop or tempo counts from what is planned.
|
||||
|
||||
Playing goes on while another tab is open, so an instrument can be changed while its pattern plays.
|
||||
It stops when another pattern is shown in the tab, when the pattern is gone and when a project is
|
||||
opened.
|
||||
|
||||
Measured (2026-10-06, e2e 64 on the CI's Windows machine): bar 1 of a pattern at 120 BPM, its notes
|
||||
at ticks 720, 960, 1440 and 1680 were planned exactly 0, 0.25, 0.75 and 1 s apart on the audio
|
||||
clock; a note drawn at tick 1800 while it played came in the next round with the playing going on.
|
||||
|
||||
## Not yet
|
||||
|
||||
No notes of other patterns in the background (ghost notes, with the song, #334), no lanes for
|
||||
pitch bend or an instrument's parameters (automation, #337), no swing. The computer keyboard does
|
||||
not play notes in this tab as it does in the Instrument tab, and there is no step input. A game
|
||||
can not play a pattern yet (#336).
|
||||
+1
@@ -14,6 +14,7 @@
|
||||
- [Fonts](Fonts)
|
||||
- [Sounds](Sounds)
|
||||
- [Instruments](Instruments)
|
||||
- [Patterns](Patterns)
|
||||
- [Animations](Animations)
|
||||
- [Curves](Curves)
|
||||
- [Tiles](Tiles)
|
||||
|
||||
Reference in new issue
Block a user