grimmdude / MidiWriterJS

♬ A JavaScript library which provides an API for programmatically generating and creating expressive multi-track MIDI files and JSON.
MIT License
547 stars 58 forks source link

Losing sound in 'wait' notes in generated midi files with multiple instruments #79

Closed riffca closed 1 year ago

riffca commented 3 years ago

Midi file generated by library has conflicts during playing together multiple instruments. If there is wait note it sounds not in sound. The noise takes away sound. But Single instrument file plays correctly. Code to reproduce and generated file attached. Listening file you can pay attention to bass guitar.

let tracks = [
        {
            midiSound: 35,
            name: 'bass',
            beat: [
                {
                    channel: 1,
                    duration: '4',
                    pitch: ['C2']
                },  
                {
                    channel: 1,
                    duration: '4',
                    pitch: ['E3']
                },          
                {
                    channel: 1,
                    wait: '4',
                    duration: '4',
                    pitch: ['C2']
                },
                {
                    channel: 1,
                    duration: '4',
                    pitch: ['C2']
                },  
                {
                    channel: 1,
                    duration: '4',
                    pitch: ['E3']
                },          
                {
                    channel: 1,
                    wait: '4',
                    duration: '4',
                    pitch: ['C2']
                },              
            ]
        },  
        {
            midiSound: 116,
            name: 'snare',
            beat: [
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },          
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },          
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },          
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },          
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                },
                {
                    channel: 10,
                    wait: '8',
                    duration: '8',
                    pitch: 'D2'
                }
            ]
        },      
    ]

    let renderTracks = []
    tracks.forEach(track=>{

        var currentTrack = new MidiWriter.Track();
        currentTrack.setTempo(120)
        currentTrack.addTrackName(track.name)
        currentTrack.addInstrumentName(track.name)

        track.beat.forEach((note)=>{
                note.velocity = Math.floor(Math.random() * (85 - 70 + 1) + 70);
                currentTrack.addEvent(
                    new MidiWriter.ProgramChangeEvent({instrument: track.midiSound})
                );
                currentTrack.addEvent([
                    new MidiWriter.NoteEvent(note),
                ])

        })
        renderTracks.push(currentTrack)
    })

    window.open(new MidiWriter.Writer(renderTracks).dataUri())

test midi.zip How it can be fixed?

grimmdude commented 1 year ago

Hi @riffca,

Opening your file in Garageband the bass track seems ok from what I can tell.

In v2.1.1 I added support for channel property in ProgramChangeEvent, so passing that in might solve whatever issue you're seeing.

new MidiWriter.ProgramChangeEvent({instrument: track.midiSound, channel: note.channel})

With that said, adding a ProgramChangeEvent for each note is unnecessary and might be related to the issue you're seeing. You should only need to set it at the beginning of the track, and if any other instrument changes are needed down the line.