Morceaux et partage
Le fichier .noisesong et le lien noise://
Ce que contient un fichier .noisesong, comment le lien noise:// l'encode, et les limites que les deux respectent.
Un morceau quitte NØISE sous l'une de deux formes lisibles par une machine : un fichier .noisesong (JSON) ou un lien noise:// (le même JSON, encodé dans une URL). Ni l'un ni l'autre ne contient d'audio. Les deux portent exactement un morceau.
Attention
Schéma 3, depuis NØISE 0.81 — sans compatibilité ascendante. Un morceau est UN groupe avec UN kit, et une section règle ses rangées DRUMS et JAM. L'app ne lit rien de plus vieux que le schéma 3 : un fichier avec schemaVersion à 2 ou absent s'ouvre sur rien, et une bibliothèque plus ancienne est mise de côté au premier lancement. Ce site refuse un tel fichier à l'envoi avec les mêmes mots. Ouvre le morceau dans l'éditeur de l'app et réexporte-le.
Le fichier .noisesong
EXPORTER, dans la plaque MORCEAUX comme dans l'éditeur, écrit un document JSON en UTF-8. L'app déclare le type de fichier comme nl.weap.noise.song (« NØISE Song », conforme à public.json, extension .noisesong) : un double-clic sur un fichier l'ouvre donc dans NØISE.
L'enveloppe
{
"version": 3,
"song": { … }
}| Champ | Type | Sens |
|---|---|---|
version | entier | La version du format de fichier ; 3 depuis 0.81. |
song | objet | Le morceau. |
Les clés sont écrites triées et le JSON est indenté. Les dates sont en ISO-8601, en UTC, sans fractions de seconde (2026-05-01T12:00:00Z) : l'app refuse les fractions de seconde.
L'objet song
{
"id": "6F1A0E9C-3D4E-4B11-9A0B-1C2D3E4F5A6B",
"name": "Amber Skyline",
"author": "NØISE",
"songDescription": "Demo song for the website",
"style": "rock",
"kit": "rock.classic",
"drums": { "feel": "straight", "preset": { "name": "LAID BACK", "energy": 0.45, "swing": 0.2, "humanize": 0.25, "live": 0.35 } },
"jam": { "intensity": 0.5, "colorLayer": false, "rhythmGuitar": true },
"tempoHint": 112,
"grooveSeed": 4422912175377245,
"schemaVersion": 3,
"createdAt": "2026-05-01T12:00:00Z",
"updatedAt": "2026-05-01T12:00:00Z",
"chart": { … }
}| Champ | Type | Obligatoire | Sens |
|---|---|---|---|
id | chaîne UUID | oui | L'identité du morceau. Importer un morceau dont l'id existe déjà dans ta bibliothèque ne fusionne jamais avec lui : l'import reçoit un UUID neuf et devient un morceau nouveau, séparé, l'id d'origine étant noté dans sourceId pour que la filiation ne se perde pas. |
name | chaîne | oui | Le nom du morceau. |
chart | objet | oui | La grille d'accords (ci-dessous). |
style | chaîne | non | Le style JAM du morceau entier : pop, rock, blues, jazz, hiphop, funk, metal. Absent = rock. Le genre de batterie en découle (pop → POP, rock → ROCK, … hiphop → HIP-HOP) et n'est pas un champ. Pendant que le morceau joue, le groupe joue le groupe du morceau ; tes propres modules DRUMS et JAM reviennent quand tu détaches le morceau. |
tempoHint | nombre | non | Le tempo du morceau ; appliqué à la session quand le morceau se charge. |
songDescription | chaîne | non | Des notes libres (notes: dans le format texte). |
author | chaîne | non | Qui l'a écrit. |
kit | chaîne | non | Le seul kit JAM du morceau entier, un id propre au style (pop.strings, rock.classic, metal.stock, …). Absent = le premier kit du style. Un kit d'un autre style est ignoré. |
drums | objet | non | La rangée DRUMS du morceau : ce dont part chaque section. Voir Les rangées. |
jam | objet | non | La rangée JAM du morceau : la même chose. |
tuning | chaîne | non | GuitarTuning.id : standard, dropD, halfStepDown, fullStepDown, dropC, openG, openD, dadgad. Appliqué à la session quand le morceau se charge, comme la tonalité et le tempo : pas une indication. Absent veut dire Standard : un morceau qui ne nomme aucun accordage est écrit en Standard, et le charger règle la session dessus. |
capo | entier | non | La case où se pose le capo du morceau, 0–9 (depuis 0.71). Appliqué au chargement comme l'accordage : absent ou 0 veut dire pas de capo, et le charger l'enlève. La grille reste dans le ton des positions ; le groupe et les détecteurs sonnent d'autant de cases plus haut. |
grooveSeed | entier | non | La graine de groove de l'auteur. Tout ce que le groupe tire au sort (lesquelles des mesures écrites de basse et de nappe, les fills, les notes d'approche, la phrase de batterie, la ligne de walking vers l'accord suivant) en découle : un morceau partagé joue pareil sur chaque Mac et chaque iPad. Absente, c'est un hash stable de l'id du morceau. L'app en écrit une à l'enregistrement d'un nouveau morceau et note la graine effective à l'export, comme la tonalité. Un entier inférieur à 2^53, pour que tout lecteur JSON, JavaScript compris, le lise exactement. |
sourceId | chaîne UUID | non | Le morceau dont celui-ci a été importé ou dérivé (la filiation des morceaux partagés). |
schemaVersion | entier | oui | 3. Tout ce qui est plus bas, ou l'absence, n'est pas lu — ni par l'app, ni par ce site. |
createdAt, updatedAt | date | oui | Horodatages. |
feel, drumStyle, drumEnergy, drumHumanize, jamIntensity, colorLayer et rhythmGuitar n'existent plus au niveau du morceau : ils vivent dans drums et jam. Un morceau venu d'une app plus récente n'échoue jamais sur une clé en plus ; les clés inconnues sont gardées sur un aller-retour.
Les rangées
Les deux mêmes blocs se trouvent sur le morceau (ce dont part chaque section) et sur une section (ce qu'elle dit elle-même). Chaque champ est optionnel et veut dire « pas réglé ici » — voir la règle de résolution.
drums — ce que la section dit au kit :
| Champ | Valeurs | Sens |
|---|---|---|
off | true / false | Le kit est silencieux pour cette section (espace solo). |
feel | un tag GrooveFeel de la liste du style (straight, halfTime, shuffle, swing, …) | Le groove : un seul feel pour la batterie ET le groupe. Un feel que le style n'offre pas se résout au premier du style. |
fill.in | crash, splash, none, choke | La cymbale sur le UN de la section. Absent = l'arrangement décide selon la transition. choke est porté par le fichier, pas encore joué (joue comme un crash). |
fill.out | auto, fill, none, break, ou le nom d'un fill (busy, tom roll, fill2, …) | Ce que fait le kit à la sortie de la section, sur la DERNIÈRE mesure de la dernière répétition. auto = l'arrangement décide ; fill = un fill quelle que soit la transition ; none = jamais ; un nom = ce fill de la banque du genre (inconnu → auto). break est porté par le fichier, pas encore joué (joue comme none). |
variation | une liste de mots | Les habillages du style. Portés par le fichier ; l'app n'a pas encore de mots pour ça. |
preset.name | STOCK, TIGHT, DRIVING, LAID BACK, LOOSE, SMOKY, QUIET, un preset à toi, ou CUSTOM | Un LABEL pour les quatre boutons ci-dessous. Les valeurs voyagent ; le nom se lit. |
preset.energy | 0–1 | À quel point le kit joue fort. |
preset.swing | 0–1 | La grille, 0 straight … 1 plein ternaire. Absent = le swing propre au feel. |
preset.humanize | 0–1 | À quel point une main varie autour de la partie. |
preset.live | 0–1 | À quel point le détail écrit (les ghosts, la variante de la 4e mesure) est révélé. |
jam — les drapeaux du groupe :
| Champ | Valeurs | Sens |
|---|---|---|
intensity | 0–1 | À quel point le groupe joue chargé. |
colorLayer | true / false | La quatrième couche (couleur) du groupe. |
rhythmGuitar | true / false | La couche de guitare rythmique du groupe, là où le style en a une. |
La règle de résolution
Chaque champ d'une rangée se résout dans un seul ordre, champ par champ :
SECTION → LA SECTION D'AVANT → MORCEAU- Une section qui règle un champ le décide. Une section qui règle
fill.inet rien d'autre décide la cymbale et suit pour tout le reste. - Une section qui laisse un champ ouvert joue ce que jouait la section d'avant — dis HALF TIME une fois et ça continue jusqu'à ce qu'autre chose le dise. Dans l'éditeur, ça se lit FOLLOW PREV.
- La première section n'a rien avant elle, donc elle prend les rangées du morceau (FOLLOW SONG).
- Le style, le kit et le genre sont ceux du morceau à chaque section. Rien qu'une section puisse dire.
- Le nom du preset ne suit que quand chaque bouton suit aussi. Une section qui a bougé un bouton sous un preset nommé se lit
CUSTOM: le nom est un label pour exactement ces quatre valeurs. Une section qui nomme un preset et ne règle aucun bouton porte le nom ET les boutons de la section d'avant — l'éditeur écrit toujours un nom avec ses valeurs. - L'auditeur n'est pas dans la liste. Un champ que le morceau laisse ouvert est complété par un défaut fixe, qui fait partie du format, pour que le même document joue le même groupe partout :
| Champ | Défaut |
|---|---|
style | rock |
kit | le premier kit du style |
drums.off | false |
drums.feel | le premier feel du style |
drums.fill.in | absent — l'arrangement décide |
drums.fill.out | auto |
drums.variation | [] |
drums.preset | STOCK : energy 0.5, le swing propre au feel, humanize 0.15, live 0.25 |
jam.intensity | 0.5 |
jam.colorLayer | false |
jam.rhythmGuitar | selon que le style ait la couche ou non |
Le swing et le live d'une section atterrissent sur l'horloge de l'app (GRID) pendant que le morceau joue, et ne sont jamais enregistrés comme les tiens ; les tiens reviennent quand tu détaches le morceau.
L'objet chart
{
"writtenKey": { "tonic": 9, "mode": "minor" },
"endBehavior": "end",
"sections": [
{
"id": "…",
"name": "INTRO",
"repeats": 2,
"energy": "sparse",
"color": "cyan",
"drums": { "feel": "straight", "fill": { "in": "none" } },
"items": [
{ "ref": { "degree": { "_0": { "degree": 1, "alteration": 0, "quality": { "minor": {} }, "alterations": [], "secondaryOf": false } } },
"duration": { "bars": 2, "ticks": 0 }, "rawText": "Am" },
{ "ref": { "absolute": { "_0": { "root": { "letter": "F", "accidental": 0 }, "type": { "major": {} }, "alterations": [] } } },
"duration": { "bars": 1, "ticks": 0 }, "rawText": "F" }
]
}
]
}| Champ | Sens |
|---|---|
writtenKey | La tonalité dans laquelle la grille a été écrite, ou absent. Les blocs en degrés se résolvent contre elle pour l'affichage ; en jouant, ils suivent le module TONALITÉ. |
endBehavior | "end" = jouer une fois, puis une frappe finale sur le premier temps, tenue une mesure, et le groupe s'arrête. Absent = boucler sans fin. Chaîne opaque, pour que de futurs comportements ne cassent jamais les anciens lecteurs. |
sections[] | L'éditeur en ajoute jusqu'à 24 ; un fichier est lu en entier. Chacune a id, name, repeats (1-16), energy (base, lift, groove, hold, riff, sparse, stop ; une valeur inconnue joue comme base), un color optionnel, et les deux rangées optionnelles drums et jam (ci-dessus). Une section ne porte ni style, ni kit, ni genre de batterie, et pas d'endFill : un fill à la sortie, c'est drums.fill.out: "fill". Un champ de rangée laissé de côté veut toujours dire : ce que jouait la section d'avant, et pour la première section la rangée du morceau ; jamais le réglage de l'auditeur. |
items[] | Au plus 32 par section. Chacun est { ref, duration, rawText }, plus un shape optionnel. (plus un push facultatif) |
ref | Exactement un parmi degree, absolute, noChord, repeatPrevious. Swift encode la charge utile sous _0. Un degré a degree 1-7, alteration (−1/0/+1), un quality optionnel (le type d'accord), alterations (b5 #5 b9 #9 #11 b13 add6 add9 add11 no3 no5) et secondaryOf (true = V/x). Un accord absolu a root (letter A-G + accidental), type, alterations et un bass optionnel. Un degree peut aussi porter bassIntervalSemitones (1–11) : une basse en slash en demi-tons au-dessus de la fondamentale de l'accord, qui transpose donc avec le ton – { "degree": 1, "bassIntervalSemitones": 4 } est C/E en C et A/C♯ en A. Sur une note de l'accord, un renversement ; en dehors, une pédale. Depuis 0.71 le groupe joue la basse ; avant, elle n'était qu'affichée. |
duration | { bars, ticks }. Les mesures sont relatives à la signature rythmique (un accord de 2 mesures fait 2 mesures en 4/4 comme en 3/4), les ticks sont un temps exact à l'intérieur de la mesure, à 24 ticks par temps : { "bars": 0, "ticks": 48 } fait donc deux temps. Les mesures sont ramenées entre 0 et 32. L'éditeur écrit n'importe quel nombre de temps (un changement sur le quatrième temps est { "bars": 0, "ticks": 72 } puis { "bars": 0, "ticks": 24 }), et une section n'a pas à tomber sur des mesures entières. |
rawText | Ce que l'utilisateur a tapé, ou ce que le bloc affichait quand il a été écrit. Affichage seulement : une grille peut montrer I là où l'accord qui sonne est Em. |
shape | Le doigté choisi par le joueur, comme tag autodescriptif : six cases, de la corde grave à la corde aiguë, x pour une corde étouffée, par ex. x32010. Les cases à partir de 10 demandent des séparateurs (8-10-10-9-8-8), et @n indique une case de départ qui ne se déduit pas des notes (x24442@2). Les cases vont de 0 à 24. Absent veut dire que l'app dessine son doigté par défaut. Les silences et les répétitions n'en portent jamais. Un doigté est un choix libre, pas une propriété de l'accord (un joueur met un voicing de Em7 sur un bloc Em) : rien ne le vérifie contre l'accord, et un tag illisible veut dire « pas de doigté », pas un morceau invalide. |
push | "eighth" ou "sixteenth" quand l'accord est anticipé (depuis 0.71) : le groupe le frappe d'autant avant sa place écrite et le tient par-dessus le temps. La place et la durée ne bougent jamais ; le compte des mesures, la tête de lecture et le défilement l'ignorent. Absent = sur le temps ; une valeur inconnue se lit comme absente ; "none" n'est jamais écrit. Dans le texte du morceau, l'anticipation est un accent circonflexe : ^G, ^^G. |
Les types d'accord sont les 24 noms du ChordType de l'app : major minor diminished augmented sus2 sus4 major7 minor7 dominant7 diminished7 halfDiminished7 minorMajor7 augmented7 add9 major9 minor9 dominant9 major11 minor11 dominant11 major13 minor13 dominant13 power. Dans le fichier, un tel nom est la clé d'un objet vide, { "minor7": {} }, sous type comme sous quality.
Ce que l'app accepte à l'import
importSongs essaie trois formes dans l'ordre et prend la première qui se décode :
- un document
.noisesong{ "version": …, "song": { … } }, - un objet song nu,
- un export de bibliothèque entière
{ "version": …, "songs": [ … ] }: chaque morceau que cette version de l'app sait lire est importé ; les illisibles sont sautés, jamais le fichier entier.
Dans chaque forme, un morceau avec un schemaVersion inférieur à 3 est sauté : l'app note pourquoi dans le journal, et rien n'est converti.
Le lien noise://
Le bouton Ouvrir dans NØISE du site, et le bouton Copier le lien à côté, produisent ce lien. L'app ne fabrique aucun lien ; elle ne fait que les lire.
noise://song?d=<payload>- schéma
noise, hôtesong, un seul paramètre de requêted; <payload>est le document.noisesongencodé compact (sans espaces, clés triées,version: 3,schemaVersion: 3) en base64url (RFC 4648 §5,-et_à la place de+et/, sans remplissage=).
Quand l'app ouvre un tel lien, elle décode la charge utile avec les mêmes règles qu'un fichier. Elle est tolérante : une charge utile arrivée avec remplissage ou encodée en pourcent se décode quand même. Comme le JSON n'est pas compressé, un lien fait à peu près 1,4 × la taille du JSON compact : un morceau de quatre sections, c'est quelques kilo-octets. Un lien plus long que ce que ton client de chat accepte se partage plutôt comme fichier.
Ouvrir un lien n'ajoute jamais rien en silence : l'app demande d'abord. Voir Import.
Où vit ta bibliothèque
Tous les morceaux sont rangés dans un seul fichier, dans le conteneur de l'app :
~/Library/Containers/com.noise-app.macos/Data/Library/Application Support/NØISE/jam-songs.jsonIl est écrit de façon atomique ; la version précédente est gardée comme jam-songs.json.bak à chaque enregistrement réussi, et un fichier principal corrompu est restauré en silence depuis la sauvegarde (la copie corrompue est gardée comme jam-songs.json.corrupt). La bibliothèque contient au plus 100 morceaux ; au-delà, les morceaux modifiés le moins récemment sont abandonnés à l'enregistrement. Une bibliothèque écrite avant le schéma 3 est mise de côté comme jam-songs.v2.json au premier lancement de 0.81, et la bibliothèque démarre vide : les morceaux ne sont pas convertis, ils sont réécrits dans l'éditeur.
Attention
Ne modifie pas jam-songs.json pendant que NØISE tourne : l'app écrit le fichier entier à chaque enregistrement et écrasera tes changements. Exporte un .noisesong, modifie celui-là, et réimporte-le.