Music Maker: Using NodeJS to Create Songs
Published: 2022-07-29 22:32:36

In my graduate school career, I had the opportunity with our evolutionary complexity lab to study creating music using neural networks and interactive genetic algorithms. It’s fun to study these two topics together since I enjoy crafting code and music. If you enjoy this too, you might enjoy Music maker, a library I created to explore generating music with code. Sonic Pi by Sam Aaron, a popular tool to teach music theory and Ruby code, inspired me to build this tool. My team from InspiredToEducate.NET enjoyed teaching a coding workshop on music using Sonic Pi. We, however, encountered a challenge of installing Sonic-Pi on a lab of computers. The workshop targets 5th-grade to 8th-grade students who have good typing skills. It would be cool if something like Sonic-Pi supported features like Blockly coding too.

In terms of musical motivations, I wanted to provide features like the following:

## Motivations 
- Like Sonic-Pi, the tool should make it easy to generate chords and scales.
- I wanted the tool to have a concept of players who can generate music over a chord progression. I believe it would be cool to grow an ecosystem of players for various time signatures and musical types.
- I wanted to support the MIDI file format for output making it possible to blend music from this tool in sequencers broadly available on the market. This also enables us to print out sheet music using the MIDI files.
- Building drum patterns can be tedious at times, I wanted to create a way to express rhythm simply.
- We desired to have a browser-based interface that a teacher could install on a Raspberry Pi or some other computer. This was a key idea from one of my teachers.  I’m focusing on building a tool that works on a local area network.  (not the broad internet)
From a coding perspective, we need to build a tool that could interface with Blockly coding someday. JavaScript became a logical choice. 

## About NG-Music-Maker

Learn more at [this GIThub repo](https://github.com/michaelprosario/ng-music-maker)

## Features

- Express server to connect MIDI file services to APIs
- Angular project to demo features
- Angular project includes a drum pattern maker
- TypeScript API for expressing ideas like chords, chord progressions, scales, and players
- Players iterate over chord progressions using a style

## Code Tour

To explore how the MIDI services work.. please inspect the examples here. (see examples project)

``` javascript

let midiServices = new MidiServices();
let scaleServices = new ScaleService(midiServices);
let chordServices = new ChordServices(midiServices);

function makeScale() {
    var file = new Midi.File();

    // Build a track
    var track = new Midi.Track();
    track.setTempo(80);
    file.addTrack(track);

    // Make a scale
    var scale = scaleServices.MakeScale("c4", ScaleType.MajorPentatonic, 2);
    for (var i = 0; i < scale.length; i++) {
        track.addNote(0, scale[i], 50);
    }

    // Write a MIDI file
    fs.writeFileSync('test.mid', file.toBytes(), 'binary');
}

function threeNotes() {
    var file = new Midi.File();

    // Build a track
    var track = new Midi.Track();
    track.setTempo(80);
    file.addTrack(track);

    let mm = midiServices;
    let beat = 50;
    track.addNote(0, mm.GetNoteNumber("c4"), beat);
    track.addNote(0, mm.GetNoteNumber("d4"), beat);
    track.addNote(0, mm.GetNoteNumber("e4"), beat);

    // Write a MIDI file
    fs.writeFileSync('test2.mid', file.toBytes(), 'binary');
}

function drumTest()
{
    var file = new Midi.File();

    // Build a track
    var track = new Midi.Track();
    track.setTempo(80);
    file.addTrack(track);

    let mm = midiServices;

    var addRhythmPattern = mm.AddRhythmPattern;
    addRhythmPattern(track, "x-x-|x-x-|xxx-|x-xx",DrumNotes.ClosedHighHat);
    fs.writeFileSync('drumTest.mid', file.toBytes(), 'binary');
}

function chordProgressions(){
    var file = new Midi.File();

    // Build a track
    var track = new Midi.Track();
    track.setTempo(80);
    file.addTrack(track);

    var chordList = new Array();
    chordList.push(new ChordChange(chordServices.MakeChord("e4", ChordType.Minor),4));
    chordList.push(new ChordChange(chordServices.MakeChord("c4", ChordType.Major),4));
    chordList.push(new ChordChange(chordServices.MakeChord("d4", ChordType.Major),4));
    chordList.push(new ChordChange(chordServices.MakeChord("c4", ChordType.Major),4));

    var chordPlayer = new SimplePlayer()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    chordPlayer = new Arpeggio1()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    chordPlayer = new RandomPlayer()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    chordPlayer = new BassPlayer1()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    chordPlayer = new BassPlayer2()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    chordPlayer = new BassPlayer3()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    chordPlayer = new OffBeatPlayer()
    chordPlayer.PlayFromChordChanges(track, chordList, 0);

    fs.writeFileSync('chordProgressions.mid', file.toBytes(), 'binary');
}


makeScale();
threeNotes();
drumTest();
chordProgressions();

```