Quick Start Guide

Get up and running with BeatBlocks in minutes

Time to Make Some Music! 🎵

First things first, let's get the BeatBlocks script in your project. Add this to your HTML:

<script src="https://ordinals.com/content/808fd704c81a98e5c776dcea26e846abf40d9a514de94feea489f8a6215bc808i0"></script>
With that set up, you'll havewindow.BeatBlockready to create some epic tunes! 🎧

Overview

This guide will help you quickly set up and use BeatBlocks to create and play generative music on the Bitcoin blockchain. We'll cover the basic steps to create a BeatBlock, initialize it, and play it back.

Prerequisites

  • Basic understanding of JavaScript and Web Audio API
  • Audio files prepared as stems (MP3 or OGG format recommended)
  • A modern web browser with Web Audio API support

Step 1: Create a BeatBlock Instance

First, create an audio context and initialize a new BeatBlock instance:

// Create an audio context
const audioContext = new (window.AudioContext || window.webkitAudioContext)();

// Initialize BeatBlock
const beatblock = new BeatBlock(audioContext);

// Make it globally accessible if needed
window.beatblock = beatblock;

This creates a new BeatBlock instance with a master processing chain that includes compression and limiting.

Step 2: Prepare Your Song Data

The song data includes a template array that defines the structure and progression of your composition. Each template section specifies the length, number of layers, and which types of layers should be included or excluded:

const songData = {
  "details": {
    "title": "Cosmic Rhythms",
    "author": "RareScrilla, Bunzy, Hathbanger, ShowerShoes",
    "bpm": 125,
    "imgId": "<INSCRIPTION_ID>"
  },
  "generationConfig": {
    "seed": "custom-upload",
    "groups": ["v1", "v2", "v3", "v4"],
    "mutexes": ["drums"]
  },
  "layers": [
    {
      "id": "ambient_pad",
      "name": "Ambient Pad",
      "loopLength": 1,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": true,
      "alignment": "end",
      "groups": [],
      "mutex": ["pads"]
    },
    {
      "id": "crash_cymbal",
      "name": "Crash Cymbal",
      "loopLength": 1,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": false,
      "alignment": "start",
      "groups": [],
      "mutex": ["splash"]
    },
    {
      "id": "rising_fx",
      "name": "Rising FX",
      "loopLength": 2,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": false,
      "alignment": "end",
      "groups": [],
      "mutex": ["rise"]
    },
    {
      "id": "main_beat",
      "name": "Main Beat",
      "loopLength": 4,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": true,
      "alignment": "end",
      "groups": ["v1"],
      "mutex": ["drums"]
    },
    {
      "id": "bass_line",
      "name": "Bass Line",
      "loopLength": 4,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": true,
      "alignment": "end",
      "groups": ["v2"],
      "mutex": ["bass"]
    },
    {
      "id": "melody_synth",
      "name": "Melody Synth",
      "loopLength": 8,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 0.8,
      "loop": true,
      "alignment": "start",
      "groups": ["v3"],
      "mutex": ["melody"]
    }
  ],
  "template": [
    {
      "length": 8,
      "layerCount": 4,
      "inclusions": ["melody", "riser"],
      "exclusions": ["drums", "bass", "vox"]
    },
    {
      "length": 8,
      "layerCount": 5,
      "inclusions": ["drums", "perc", "riser", "melody"],
      "exclusions": ["bass"]
    },
    {
      "length": 16,
      "layerCount": 6,
      "inclusions": ["melody", "drums", "riser", "bass"],
      "exclusions": []
    }
  ]
};

This JSON structure defines the metadata for your BeatBlock, including details about the composition, generation configuration, and individual audio layers with their properties.

Step 3: Initialize and Load

Initialize the BeatBlock with your song data and load the audio files:

// Initialize with song data
beatblock.initialize(songData).then(() => {
  console.log('All audio loaded and ready to play');
}).catch(error => {
  console.error('Error loading audio:', error);
});

The loadAllAudio() method returns a Promise that resolves when all audio files are loaded.

Step 4: Playback Controls

Implement basic playback controls:

// Play the BeatBlock
beatblock.play();

// Pause playback
beatblock.pause();

// Stop playback and reset to beginning
beatblock.stop();

// Adjust master volume (0.0 to 1.0)
beatblock.setVolume(0.8);

Step 5: Event Handling

Listen for events to update your UI or trigger actions:

// Loading progress and info events
beatblock.on('info', (message) => {
  console.log(`Info: ${message}`);
});

beatblock.on('error', (errorMessage) => {
  console.error(`Error: ${errorMessage}`);
});

// Playback state changes
beatblock.on('end', (message) => {
  console.log('Playback ended:', message);
  document.getElementById('play-button').classList.remove('active');
});

// You can also listen for other events
beatblock.on('beat', (beatNumber) => {
  console.log(`Current beat: ${beatNumber}`);
  // Flash beat indicator
  document.getElementById('beat-indicator').classList.add('flash');
  setTimeout(() => {
    document.getElementById('beat-indicator').classList.remove('flash');
  }, 100);
});

beatblock.on('bar', (barNumber) => {
  console.log(`Current bar: ${barNumber}`);
  document.getElementById('bar-counter').textContent = barNumber;
});

Step 6: Inscribing to Bitcoin

To inscribe your BeatBlock to the Bitcoin blockchain:

  1. Export your BeatBlock JSON

    // Get the complete BeatBlock JSON
    const beatblockJson = beatblock.getBeatBlockData();
    
    // Save to file or copy to clipboard
    const jsonString = JSON.stringify(beatblockJson, null, 2);
  2. Use an Ordinals wallet to inscribe

    # Using the ord CLI tool
    ord wallet inscribe beatblock.json \
      --fee-rate 10 \
      --content-type application/json

Once inscribed, your BeatBlock will have a unique inscription ID that can be used to retrieve and play it.

Complete Example

Here's a complete example that puts everything together:

// Initialize audio context and BeatBlock
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const beatblock = new BeatBlock(audioContext);

// Define song data
const songData = {
  "details": {
    "title": "Cosmic Rhythms",
    "author": "RareScrilla, Bunzy, Hathbanger, ShowerShoes",
    "bpm": 125,
    "imgId": "<INSCRIPTION_ID>"
  },
  "generationConfig": {
    "seed": "custom-upload",
    "groups": ["v1", "v2", "v3", "v4"],
    "mutexes": ["drums"]
  },
  "layers": [
    {
      "id": "ambient_pad",
      "name": "Ambient Pad",
      "loopLength": 1,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": true,
      "alignment": "end",
      "groups": [],
      "mutex": ["pads"]
    },
    {
      "id": "main_beat",
      "name": "Main Beat",
      "loopLength": 4,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": true,
      "alignment": "end",
      "groups": ["v1"],
      "mutex": ["drums"]
    },
    {
      "id": "bass_line",
      "name": "Bass Line",
      "loopLength": 4,
      "path": "/content/<INSCRIPTION_ID>",
      "volume": 1,
      "loop": true,
      "alignment": "end",
      "groups": ["v2"],
      "mutex": ["bass"]
    }
  ],
  "template": [
    {
      "length": 8,
      "layerCount": 3,
      "inclusions": ["drums", "bass"],
      "exclusions": ["melody", "vox"]
    },
    {
      "length": 16,
      "layerCount": 4,
      "inclusions": ["drums", "bass", "melody"],
      "exclusions": ["vox"]
    }
  ]
};

// Set up UI event listeners
document.getElementById('play-button').addEventListener('click', () => beatblock.play());
document.getElementById('pause-button').addEventListener('click', () => beatblock.stop());
document.getElementById('stop-button').addEventListener('click', () => beatblock.stop());

// Initialize and load
async function init() {
  try {
    // Show loading indicator
    document.getElementById('loading').style.display = 'block';
    
    // Initialize with song data and listen for events
    beatblock.on('info', (message) => {
      console.log(`Info: ${message}`);
    });
    
    beatblock.on('error', (errorMessage) => {
      console.error(`Error: ${errorMessage}`);
      document.getElementById('error').textContent = errorMessage;
      document.getElementById('error').style.display = 'block';
    });
    
    beatblock.on('end', (message) => {
      console.log('Playback ended:', message);
      document.getElementById('play-button').classList.remove('active');
    });
    
    // Initialize the BeatBlock with song data
    await beatblock.initialize(songData);
    
    // Hide loading indicator
    document.getElementById('loading').style.display = 'none';
    document.getElementById('controls').style.display = 'block';
    
    // Listen for beat and bar events
    beatblock.on('beat', (beatNumber) => {
      document.getElementById('beat-indicator').classList.add('flash');
      setTimeout(() => {
        document.getElementById('beat-indicator').classList.remove('flash');
      }, 100);
    });
    
    beatblock.on('bar', (barNumber) => {
      document.getElementById('bar-counter').textContent = barNumber;
    });
    
    console.log('BeatBlock initialized and ready to play!');
  } catch (error) {
    console.error('Error initializing BeatBlock:', error);
    document.getElementById('error').textContent = error.message;
    document.getElementById('error').style.display = 'block';
  }
}

// Start initialization
init();