Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!DOCTYPE html>
<html>

<head>
  <script src="https://cdn.jsdelivr.net/npm/@magenta/music@1.7.0"></script>
</head>

  <body>
    <!-- loading animation visual. By default not displayed. Display triggered by showLoading() -->
    <div id="loader" >
      <div class="load-1">
        <p>Loading...</p>
        <br />
        <!-- first line is invisible. used for vertical alignment purposes -->
        <div class="line" style="height:65px;width:0px;background-color: rgb(255,0,0,0);"></div>
        <div class="line"></div>
        <div class="line"></div>
        <div class="line"></div>
        <div class="line"></div>
        <div class="line"></div>
      </div>
    </div>

    <div id="container">

      <!-- Begin original Section   -->
      <div class="radioGroup">
        <label> <input type="radio" name="player" id="synth" value="synth" checked="checked" onclick="toggleSoundFont()"> Synth</label>
        <label><input type="radio" name="player" value="soundFont" id="soundFont" onclick="toggleSoundFont()">SoundFontPlayer</label>
      </div>

      <br />
      <hr style="border-color:white;" />
      <br />

      <div id="originalSelect" class="select-style">
        <select>
          <option value="0">Whip It</option>
          <option value="1">Freedom Of Choice</option>
          <option value="2">Beautiful World</option>
          <option value="3">Gut Feeling</option>
        </select>
      </div>

      <button onclick="playOriginal()"> Play original input </button>
      <button onclick="stop()">Stop </button>

      <br />

      <input type="range" min="0" max="20" value="0" class="slider" id="trimStart">
      <p>Trim start (s): <span class="sliderValue"></span></p>

      <br />

      <canvas id="originalCanvas"></canvas>

      <hr />
      <hr />

      <!-- Begin Interpolate Section   -->

      <div id="interpolateSelect1" class="select-style">
        <select>
          <option value="0" selected="selected">Whip It</option>
          <option value="1">Freedom Of Choice</option>
          <option value="2">Beautiful World</option>
          <option value="3">Gut Feeling</option>
        </select>
      </div>
      <div id="interpolateSelect2" class="select-style">
        <select>
          <option value="0">Whip It</option>
          <option value="1" selected="selected">Freedom Of Choice</option>
          <option value="2">Beautiful World</option>
          <option value="3">Gut Feeling</option>
        </select>
      </div>
      <button onclick="interpolate()"> Interpolate Input </button>
      <button onclick="playInterpolation()">  Play Interpolation  </button>
      <button onclick="stop()">Stop </button>

      <br />

      <input type="range" min="5" max="20" value="10" data-multiplier="0.1" class="slider" id="vaeTemp">
      <p>Temperature: <span class="sliderValue"></span></p>

      </br>

      <input type="range" min="5" max="8" value="5" class="slider" data-multiplier="1" data-exponent="2" id="chunkSize">
      <p>Chunk Size: <span class="sliderValue"></span></p>

      </br>

      <input type="range" min="10" max="60" value="30" class="slider" id="chunkDuration">
      <p>Chunk Duration: <span class="sliderValue"></span></p>

      </br>

      <canvas id="interpolatedCanvas"></canvas>

      <hr />
      <hr />

      <!-- Begin Generate Section   -->

      <button onclick="generate()">  Generate</button>
      <button onclick="playGenerated()">  Play Generated  </button>
      <button onclick="stop()">Stop </button>

      </br>

      <input type="range" min="10" max="200" value="30" class="slider" id="rnnSteps">
      <p>Step: <span class="sliderValue"></span></p>

      </br>

      <input type="range" min="5" max="20" value="10" data-multiplier="0.1" class="slider" id="rnnTemp">
      <p>Temperature: <span class="sliderValue"></span></p>

      </br>

      <canvas id="generatedCanvas"></canvas>

    </div> <!-- container -->
  </body>
</html>

              
            
!

CSS

              
                
    canvas {
      border: 1px solid pink;
      margin: 5px;
      height: 200px;
      width:100%;
    }
    p,label {
      font-family: Arial;
      display: inline-block;
      color: white;
      margin: 5px;
    }
    button{
      border: 1px solid pink;
      color: coral;
      background-color: black;
      padding: 5px;
      margin: 5px;
      cursor: pointer;
    }
    button:hover {
      border: 1px solid coral;
      color: pink;
    }
    html {
      background-color: black;
    }

    .slider {
      width: 40%;
      height: 3px;
      margin: 5px;
      border-radius: 5px;
      background: #a5ff9b;
      outline: none;
      opacity: 0.7;
      -webkit-transition: .2s;
      -webkit-appearance: none;
      transition: opacity .2s;
    }

    .slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      appearance: none;
      width: 20px;
      height: 10px;
      border-radius: 10%;
      border: solid 2px #53f442;
      border-bottom : solid 4px #53f442;
      background-color: black;
      cursor: pointer;
    }

    .slider::-moz-range-thumb {
      width: 25px;
      height: 25px;
      border-radius: 50%;
      background: #53f442;
      cursor: pointer;
    }

    .select-style {
        border: 1px solid black;
        display: inline-block;
        width:140px;
        background: black;
        margin:5px;

    }
    .select-style:hover {
        border-bottom: 1px solid #a5ff9b;
    }

    hr{
      border-color: black;
    }

    .select-style select {
        padding: 5px;
        width: 100%;
        color:#a5ff9b;
        border:none;
        box-shadow: none;
        background: black;
    }

    .select-style select:focus {
        outline: none;
    }

    .radioGroup {
      margin: 5px;
      border: 1px solid #a5ff9b;
      border-radius: 20px;
      width: 210px;
    }
    .radioGroup label{
      color:#a5ff9b;
      border: 1px solid black;
      border-radius: 20px;
      padding:4px;
    }

    .radioGroup label:hover{
        border: 1px solid #a5ff9b;
    }

    .radioGroup input{
      position: absolute;
      opacity: 0;
      cursor: pointer;
      height: 0;
      width: 0;
    }

  #loader{
    position: fixed;
    left:50%;
    top:50%;
    transform: translate(-50px,-50px);
    width: 100px;
    height: 100px;
    padding: 20px 20px 20px;
    border-radius: 0px;
    background-color: rgb(100,100,100,0.5);
  }

  .line {
    display: inline-block;
    width: 15px;
    height: 35px;
    border-radius: 2px;
    background-color: pink;
    vertical-align: bottom;
  }

  .load-1 .line:nth-last-child(1) {animation: loadingA 1s 0.9s infinite;}
  .load-1 .line:nth-last-child(2) {animation: loadingA 1s 0.6s infinite;}
  .load-1 .line:nth-last-child(3) {animation: loadingA 1s 0.3s infinite;}
  .load-1 .line:nth-last-child(4) {animation: loadingA 1s 0s infinite;}
  .load-1 .line:nth-last-child(5) {animation: loadingA 1s 0.7s infinite;}

  @keyframes loadingA {
    0 {height: 35px;}
    50% {height: 65px;}
    100% {height: 25px;}
  }
              
            
!

JS

              
                // set input (linked from external source)
const WHIP_IT_SEQUENCE = whipIt;
const FREEDOM_OF_CHOICE_SEQUENCE = freedomOfChoice;
const BEAUTIFUL_WORLD_SEQUENCE = beautifulWorld;
const GUT_FEELING_SEQUENCE = gutFeeling;

// array of original note sequences
const originals = [
  WHIP_IT_SEQUENCE,
  FREEDOM_OF_CHOICE_SEQUENCE,
  BEAUTIFUL_WORLD_SEQUENCE,
  GUT_FEELING_SEQUENCE
];

// Initialize the machine learning model.
initModel();
function initModel(){
  showLoading();
  // https://tensorflow.github.io/magenta-js/music/modules/_music_vae_model_.html
  music_vae = new mm.MusicVAE(
  "https://storage.googleapis.com/magentadata/js/checkpoints/music_vae/mel_4bar_small_q2"
  );
  music_vae.initialize();
  // https://tensorflow.github.io/magenta-js/music/modules/_music_rnn_model_.html
  music_rnn = new mm.MusicRNN(
    "https://storage.googleapis.com/magentadata/js/checkpoints/music_rnn/melody_rnn"
  );
  music_rnn.initialize();
  hideLoading();
}


// load default player
// https://tensorflow.github.io/magenta-js/music/modules/_core_player_.html
let player = new mm.Player(false, {
  run: note => viz.redraw(note),
  stop: () => {}
});

// configure visualization for canvas
const config = {
  noteHeight: 6,
  pixelsPerTimeStep: 30,
  noteSpacing: 1,
  noteRGB: "8, 41, 64",
  activeNoteRGB: "240, 84, 119"
};

// show loading animation
function showLoading(){
  let loader = document.querySelector('#loader');
  loader.style.display = "inline-block";
}
// hide loading animation
function hideLoading(){
  let loader = document.querySelector('#loader');
  loader.style.display = "none";
}

toggleSoundFont();
// inits new music player and adjusts UI to reflect current UI player
function toggleSoundFont() {
  showLoading();
  if (player.isPlaying()) {
    player.stop();
  }
  // adjust UI
  let playerInputs = document.querySelectorAll('input[name="player"]');
  for (let input of playerInputs) {
    input.parentElement.style.backgroundColor = "black";
    input.parentElement.style.color = "#a5ff9b";
  }
  let checkedInput = document.querySelector('input[name="player"]:checked');
  checkedInput.parentElement.style.color = "black";
  checkedInput.parentElement.style.backgroundColor = "#a5ff9b";

  if (checkedInput.value == "soundFont") {
    // use soundfont player
    // https://tensorflow.github.io/magenta-js/music/classes/_core_player_.soundfontplayer.html
    player = new mm.SoundFontPlayer(
      "https://storage.googleapis.com/magentadata/js/soundfonts/sgm_plus",
      undefined,
      undefined,
      undefined,
      {
        run: note => viz.redraw(note),
        stop: () => {}
      }
    );
  } else {
    // use soundfont player
    // https://tensorflow.github.io/magenta-js/music/classes/_core_player_.player.html
    player = new mm.Player(false, {
      run: note => viz.redraw(note),
      stop: () => {}
    });
  }
  hideLoading();
}
// initialize UI slider values
let sliders = document.querySelectorAll(".slider");
sliders.forEach(slider => {
 let setVal = function() {
    let textElement = slider.nextElementSibling.querySelector(".sliderValue");
    // data-multiplier is used for sliders where value should be a scale of a multiple
    let m = slider.getAttribute("data-multiplier");
    if (m == "" || m == null) {
      m = 1;
    }
    // data-exponent is used for sliders where value should be on exponential scale
    let e = slider.getAttribute("data-exponent");
    // adjust slider value displayed on UI
    if (e != "" && e != null) {
      textElement.innerHTML = Math.pow(e, slider.value * m);
    } else {
      textElement.innerHTML = Math.round(slider.value * m * 10) / 10;
    }
  };

  setVal();
  slider.oninput = setVal;
});

// splits an input note sequence into and array of note sequences based on instrument type
function sequenceInstrumentSplit(seq) {

  let sequenceArray = [];
  let instrumentNotes = new Map();

  let instrumentIndex = 0;
  seq.notes.forEach(note => {
    if (!instrumentNotes.has(note.instrument)) {
      instrumentNotes.set(note.instrument, new Array() );
    }
    instrumentNotes.get(note.instrument).push(note);
  });

  instrumentNotes.forEach((instrumentNotes, key) => {
    // perform a deepcopy of seq
    let instrumentSeq = mm.sequences.clone(seq);
    instrumentSeq.notes = instrumentNotes;
    sequenceArray.push(instrumentSeq);
  });

  return sequenceArray;
}

// funtion to combine array note sequences into one note sequence
// basically the reverse of mm.sequences.split()
function sequenceArrayCombine(sequenceArray) {
  let combinedSequence = sequenceArray[0];
  for (let i = 1; i < sequenceArray.length; i++) {
    combinedSequence.notes = combinedSequence.notes.concat(
      sequenceArray[i].notes
    );
  }
  return combinedSequence;
}

// trims from start of input sequences based on the UI "trim" slider values
function trimSequences(sequences) {

  let trimmedSequences = [];
  let startTrim = document.querySelector("#trimStart").value;
  sequences.forEach(seq => {
    trimmedSequences.push(mm.sequences.trim(seq, startTrim, seq.totalTime));
  });

  return trimmedSequences;
}

// helper function to interpolates 2 instrument note sequences by chunking sequences into sections then
// interpolating between the pairwise sections and returns a single sequence
function interpolateInstrumentTracks(seq1, seq2) {

  // input parameters driven by UI
  let vae_temp = Number(document.querySelector("#rnnTemp").value * 0.1);
  let chunkDuration = Number(document.querySelector("#chunkDuration").value);
  let chunkSize = Math.pow(2, document.querySelector("#chunkSize").value);

  // https://tensorflow.github.io/magenta-js/music/modules/_core_sequences_.html#quantizenotesequence
  let quantizedSeq1 = mm.sequences.quantizeNoteSequence(seq1, 4);
  let quantizedSeq2 = mm.sequences.quantizeNoteSequence(seq2, 4);
  // https://tensorflow.github.io/magenta-js/music/modules/_core_sequences_.html#split
  let seq1Chunks = mm.sequences.split(quantizedSeq1, chunkSize);
  let seq2Chunks = mm.sequences.split(quantizedSeq2, chunkSize);
  let minNumChunks = Math.min(seq1Chunks.length, seq2Chunks.length);

  let promises = [];
  for (let i = 0; i < minNumChunks; i++) {
    promises.push(
      music_vae.interpolate([seq1Chunks[i], seq2Chunks[i]], 3, vae_temp)
    );
  }

  return Promise.all(promises).then(interpolatedArrays => {
    let interpolatedSequences = [];
    let durations = [];
    interpolatedArrays.forEach(interpolatedArray => {
      interpolatedSequences.push(interpolatedArray[1]);
      durations.push(chunkDuration);
    });
    return mm.sequences.concatenate(interpolatedSequences, durations);
  });
}

// Main function to interpolate 2 sequences and output a single sequence
function interpolateSequencePair(seq1, seq2) {
  let seq1DeepCopy = mm.sequences.clone(seq1);
  let seq2DeepCopy = mm.sequences.clone(seq2);

  // seq1DeepCopy = mm.sequences.mergeInstruments(seq1DeepCopy);
  // seq2DeepCopy = mm.sequences.mergeInstruments(seq2DeepCopy);

  let instrumentSeqArray1 = sequenceInstrumentSplit(seq1DeepCopy);
  let instrumentSeqArray2 = sequenceInstrumentSplit(seq2DeepCopy);

  let minInstrumentSeq = Math.min(
    instrumentSeqArray1.length,
    instrumentSeqArray2.length
  );

  let promises = [];
  for (let i = 0; i < minInstrumentSeq; i++) {
    promises.push(
      Promise.resolve(
        interpolateInstrumentTracks(
          instrumentSeqArray1[i],
          instrumentSeqArray2[i]
        )
      )
    );
  }

    return Promise.all(promises).then(interpolatedSequences => {
    return Promise.resolve(sequenceArrayCombine(interpolatedSequences));
  });
}

// function to stop audio playing
function stop() {
  if (player.isPlaying()) {
    player.stop();
    return;
  }
}

function playOriginal() {

  if (player.isPlaying()) {
    player.stop();
    return;
  }
  showLoading();
  let songIndex = document.querySelector("#originalSelect select").value;
  let seq = originals[songIndex];
  let startTrim = document.querySelector("#trimStart").value;
  // https://tensorflow.github.io/magenta-js/music/modules/_core_sequences_.html#trim
  seq = mm.sequences.trim(seq, startTrim, seq.totalTime);
  // https://tensorflow.github.io/magenta-js/music/modules/_core_sequences_.html#quantizenotesequence
  seq = mm.sequences.quantizeNoteSequence(seq, 4);

  viz = new mm.PianoRollCanvasVisualizer(
    seq,
    document.getElementById("originalCanvas"),
    config
  );
  player.start(seq);
  hideLoading();
}

let interpolatedNoteSequence;

function interpolate() {
  showLoading();
  // setTimeout is only to allow showLoading() time to display properyly
  setTimeout(function(){
    let song1Index = document.querySelector("#interpolateSelect1 select").value;
    let song2Index = document.querySelector("#interpolateSelect2 select").value;

    interpolateSequencePair(originals[song1Index], originals[song2Index]).then(
      seq => {
        viz = new mm.PianoRollCanvasVisualizer(
          seq,
          document.getElementById("interpolatedCanvas"),
          config
        );
        interpolatedNoteSequence = seq;
        hideLoading();
      }
    );
  },100);
}

function playInterpolation() {
  showLoading();
  if (player.isPlaying()) {
    player.stop();
    return;
  }

  player.start(interpolatedNoteSequence);
  hideLoading();
}

let generatedNoteSequence;

function generate() {

  if(interpolatedNoteSequence === undefined){
    alert("Needs interpolated input, to genreate from.");
    return;
  }
  showLoading();
  setTimeout(function(){

    rnn_steps = Number(document.querySelector("#rnnSteps").value);
    rnn_temperature = Number(document.querySelector("#rnnTemp").value * 0.1);
    music_rnn
      .continueSequence(interpolatedNoteSequence, rnn_steps, rnn_temperature)
      .then(sample => {
        viz = new mm.PianoRollCanvasVisualizer(
          sample,
          document.getElementById("generatedCanvas"),
          config
        );
        generatedNoteSequence = sample;
        hideLoading();
      });
   },100);
}

// Plays audio of generated note sequence in the browser
function playGenerated() {
  if(generatedNoteSequence === undefined){
    alert("Needs have generated input to play.");
    return;
  }

  showLoading();
  if (player.isPlaying()) {
    player.stop();
    return;
  }
  player.start(generatedNoteSequence);
  hideLoading();
}
              
            
!
999px

Console