Generator API Reference
Complete reference for the BeatBlocks Generator API
Overview
The BeatBlocks Generator API provides tools for procedurally generating music compositions from templates. It handles layer selection, arrangement creation, and ensures musical coherence based on configurable rules.
Basic Usage
// Generate a composition from a template
const beatBlock = new BeatBlock(audioContext);
// Define input data with template
const inputData = {
details: {
title: "Generated Composition",
author: "BeatBlocks Creator",
bpm: 120
},
layers: [
// Layer definitions
],
generationConfig: {
seed: 12345,
groups: ["main", "alt"],
mutexes: ["drums", "bass"]
},
template: [
{
length: 8,
layerCount: 3,
inclusions: ["drums"],
exclusions: []
},
{
length: 4,
layerCount: 5,
inclusions: ["drums", "bass"],
exclusions: ["fx"]
}
]
};
// Generate the arrangement
const arrangedSong = await beatBlock.generate(inputData);
// Initialize with the generated arrangement
await beatBlock.initialize(arrangedSong);
Generation Method
generate(songData)
Generates a complete arrangement from a template-based song definition.
Parameters
songData
- A BeatBlockInputData object containing template and layer definitions
Returns
Promise<BeatBlockInputData>
- The complete song data with generated arrangement
Example
const generatedSong = await beatBlock.generate({
details: {
title: "My Generated Song",
author: "BeatBlocks Creator",
bpm: 90
},
generationConfig: {
seed: 42,
groups: ["aa", "bb", "cc"],
mutexes: ["drums", "bass", "vox"]
},
layers: [
{
id: "kick-1",
loopLength: 2,
path: "/content/kick-1.opus",
volume: 1,
loop: true,
alignment: "start",
groups: ["aa"],
mutex: ["drums"],
weight: 10
},
{
id: "snare-1",
loopLength: 2,
path: "/content/snare-1.opus",
volume: 0.8,
loop: true,
alignment: "start",
groups: ["bb"],
mutex: ["drums"],
weight: 5
},
{
id: "bass-1",
loopLength: 4,
path: "/content/bass-1.opus",
volume: 0.9,
loop: true,
alignment: "start",
groups: ["aa"],
mutex: ["bass"],
weight: 8
}
],
template: [
{
length: 4,
layerCount: 2,
inclusions: ["drums"],
exclusions: []
},
{
length: 8,
layerCount: 4,
inclusions: ["drums", "bass"],
exclusions: []
},
{
length: 4,
layerCount: 1,
inclusions: [],
exclusions: ["drums"]
}
]
});
console.log(generatedSong.arrangement);
Random Generation
mulberry32(seed)
Creates a deterministic random number generator based on a seed value.
Parameters
seed
- A numeric seed value
Returns
Function
- A function that returns a random number between 0 and 1
Example
// Create a seeded random number generator
const random = beatBlock.mulberry32(12345);
// Generate random numbers
const randomValue1 = random(); // e.g., 0.23456789
const randomValue2 = random(); // e.g., 0.87654321
// Using the same seed will produce the same sequence
const sameRandom = beatBlock.mulberry32(12345);
const sameValue1 = sameRandom(); // Will be 0.23456789
const sameValue2 = sameRandom(); // Will be 0.87654321
selectWeightedLayer(layers, random)
Selects a layer from an array based on weight values.
Parameters
layers
- Array of layers with optional weight propertiesrandom
- Random number generator function
Returns
Layer
- The selected layer
Example
// Array of layers with weights
const layers = [
{ id: "layer1", weight: 10 },
{ id: "layer2", weight: 5 },
{ id: "layer3", weight: 1 }
];
// Create random generator
const random = beatBlock.mulberry32(12345);
// Select a layer based on weights
// layer1 has 10/16 chance, layer2 has 5/16 chance, layer3 has 1/16 chance
const selectedLayer = selectWeightedLayer(layers, random);
Generation Algorithm
How Generation Works
The BeatBlocks generation algorithm follows these steps:
- Initialize Random Generator: Create a deterministic random number generator using the provided seed.
- Process Template: For each section in the template:
- Determine how many layers to include based on the layerCount property
- Filter layers based on inclusions and exclusions
- Ensure mutually exclusive layers don't conflict (using mutex groups)
- Select layers based on their weights
- Create Arrangement: Build the final arrangement with selected layers for each section.
- Return Complete Song: Return the original song data with the generated arrangement.
Pseudocode
function generate(songData) {
// Initialize random generator with seed
const random = mulberry32(songData.generationConfig.seed);
// Create empty arrangement
const arrangement = [];
// Process each template section
for (const templateSection of songData.template) {
// Create section with specified length
const section = {
length: templateSection.length,
layers: []
};
// Get available layers based on inclusions/exclusions
let availableLayers = songData.layers.filter(layer => {
// Check if layer matches inclusion/exclusion criteria
const matchesInclusions = templateSection.inclusions.length === 0 ||
templateSection.inclusions.some(tag => layer.mutex.includes(tag));
const matchesExclusions = !templateSection.exclusions.some(tag =>
layer.mutex.includes(tag));
return matchesInclusions && matchesExclusions;
});
// Track selected mutex groups to avoid conflicts
const selectedMutexes = new Set();
// Select layers up to layerCount
for (let i = 0; i < templateSection.layerCount; i++) {
// Filter out layers with mutex conflicts
const nonConflictingLayers = availableLayers.filter(layer =>
!layer.mutex.some(mutex => selectedMutexes.has(mutex))
);
if (nonConflictingLayers.length === 0) break;
// Select layer based on weights
const selectedLayer = selectWeightedLayer(nonConflictingLayers, random);
// Add layer to section
section.layers.push(selectedLayer);
// Mark mutex groups as used
selectedLayer.mutex.forEach(mutex => selectedMutexes.add(mutex));
// Remove selected layer from available layers
availableLayers = availableLayers.filter(layer => layer.id !== selectedLayer.id);
}
// Add section to arrangement
arrangement.push(section);
}
// Return complete song data with arrangement
return {
...songData,
arrangement
};
}
Complete Example
A complete example of using the BeatBlocks Generator API:
// Initialize audio context and BeatBlock
const audioContext = new AudioContext();
const beatBlock = new BeatBlock(audioContext);
// Define input data with template
const inputData = {
details: {
title: "Procedural Beat",
author: "BeatBlocks Creator",
bpm: 90
},
generationConfig: {
seed: Math.floor(Math.random() * 1000000), // Random seed
groups: ["main", "alt", "fx"],
mutexes: ["drums", "bass", "melody", "vox"]
},
layers: [
// Drum layers
{
id: "kick-1",
loopLength: 2,
path: "/content/kick-1.opus",
volume: 1,
loop: true,
alignment: "start",
groups: ["main"],
mutex: ["drums"],
weight: 10
},
{
id: "kick-2",
loopLength: 2,
path: "/content/kick-2.opus",
volume: 1,
loop: true,
alignment: "start",
groups: ["alt"],
mutex: ["drums"],
weight: 5
},
// Bass layers
{
id: "bass-1",
loopLength: 4,
path: "/content/bass-1.opus",
volume: 0.9,
loop: true,
alignment: "start",
groups: ["main"],
mutex: ["bass"],
weight: 8
},
{
id: "bass-2",
loopLength: 4,
path: "/content/bass-2.opus",
volume: 0.9,
loop: true,
alignment: "start",
groups: ["alt"],
mutex: ["bass"],
weight: 4
},
// Melody layers
{
id: "melody-1",
loopLength: 8,
path: "/content/melody-1.opus",
volume: 0.8,
loop: true,
alignment: "start",
groups: ["main"],
mutex: ["melody"],
weight: 6
},
// FX layers
{
id: "fx-1",
loopLength: 1,
path: "/content/fx-1.opus",
volume: 0.7,
loop: false,
alignment: "start",
groups: ["fx"],
mutex: [],
weight: 3
}
],
template: [
// Intro section
{
length: 4,
layerCount: 1,
inclusions: ["drums"],
exclusions: []
},
// Build-up section
{
length: 4,
layerCount: 2,
inclusions: ["drums", "bass"],
exclusions: []
},
// Main section
{
length: 8,
layerCount: 3,
inclusions: ["drums", "bass"],
exclusions: []
},
// Break section
{
length: 4,
layerCount: 1,
inclusions: [],
exclusions: ["drums"]
},
// Outro section
{
length: 4,
layerCount: 2,
inclusions: ["drums"],
exclusions: []
}
]
};
// Generate and play
async function generateAndPlay() {
try {
// Generate arrangement
const generatedSong = await beatBlock.generate(inputData);
console.log("Generated arrangement:", generatedSong.arrangement);
// Initialize player with generated song
await beatBlock.initialize(generatedSong);
// Play the composition
await beatBlock.play();
// Export the generated song as JSON
const jsonString = JSON.stringify(generatedSong, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
// Create download link
const a = document.createElement('a');
a.href = url;
a.download = 'generated-beatblock.json';
a.textContent = 'Download Generated BeatBlock';
document.body.appendChild(a);
} catch (error) {
console.error("Generation error:", error);
}
}
// Start generation when page loads
document.addEventListener('DOMContentLoaded', generateAndPlay);