Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sequenceProtoToMidi used on a quantizedSequence generates a MIDI file without song (perhaps: unquantizeSequence is bugging) #462

Closed
Jars-of-jam-Scheduler opened this issue Jun 7, 2020 · 4 comments

Comments

@Jars-of-jam-Scheduler
Copy link

Jars-of-jam-Scheduler commented Jun 7, 2020

Hi everyone,

Summary

  1. The API I speak about

  2. The context

  3. The problem: Actual result + Expected result

  4. What I already have tried

  5. Clues to help you to help me

  6. Minimal and Testable Example: Prerequisites and Steps to follow + Sources


The API I speak about

https://github.com/magenta/magenta-js , https://magenta.github.io/magenta-js/music/

The context

I try to generate a MIDI file that I can play with VLC on Ubuntu 18.04.4. Here are the steps of my instructions flow:

  1. I load a notes sequence array with arbitrary notes data
  2. I quantize it
  3. I get the bytes array of the MIDI format of these quantized notes
  4. I save it into a MIDI file that I download

The problem

Actual result

Step 4: the output MIDI file seems to contain the notes. However, when I play it, I hear nothing.

Expected result

Step 4: the output MIDI file contains the notes. When I play it, I hear the notes.

What I already have tried

Step 2: I don't quantize it
Step 3: I get the bytes array of the MIDI format of these not-quantized notes
Step 4: I save it into a MIDI file that I download

This way, the output MIDI files contains the notes. When I play it, I hear the notes.

Clues to help you to help me

Calling mm.sequenceProtoToMidi( mm.sequences.unquantizeSequence(quantized_sequence) ) triggers the same problem (in other words: calling mm.sequences.unquantizeSequence on the quantized sequence and then calling mm.sequenceProtoToMidi on it) .

However as I explained before: if I use a directly not-quantized sequence, it works.

Add to this previous fact this new one: your function sequenceProtoToMidi uses unquantizeSequence when it's necessary (i.e.: when isUnquantizedSequence returns true).

So I wonder if your function unquantizeSequence() works correctly or if it's bugging.

Minimal and Testable Example

Prerequisites and Steps to follow

Open the following file in your browser. It will automatically download the MIDI file that does not work as expected.

To reproduce what I've tried, follow these steps:

  1. Comment the line const quantizedSequence = mm.sequences.quantizeNoteSequence(sequence, 1)
  2. Replace the line var midi_bytes_array = mm.sequenceProtoToMidi(quantizedSequence) with var midi_bytes_array = mm.sequenceProtoToMidi(sequence)
  3. [OPTIONAL] Replace the line saveByteArray("test_with_quantized_sequence.midi", midi_bytes_array); with saveByteArray("test_with_not_quantized_sequence.midi", midi_bytes_array);

Sources

File: index.HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Music</title>
    <script src="https://cdn.jsdelivr.net/npm/@magenta/music"></script>
</head>
<body>

<script>
        const sequence = {
          totalTime: 8,
          notes: [
            {pitch: 60, startTime: 0.0, endTime: 0.5},
            {pitch: 60, startTime: 0.5, endTime: 1.0},
            {pitch: 67, startTime: 1.0, endTime: 1.5},
            {pitch: 67, startTime: 1.5, endTime: 2.0},
            {pitch: 69, startTime: 2.0, endTime: 2.5},
            {pitch: 69, startTime: 2.5, endTime: 3.0},
            {pitch: 67, startTime: 3.0, endTime: 4.0},
            {pitch: 65, startTime: 4.0, endTime: 4.5},
            {pitch: 65, startTime: 4.5, endTime: 5.0},
            {pitch: 64, startTime: 5.0, endTime: 5.5},
            {pitch: 64, startTime: 5.5, endTime: 6.0},
            {pitch: 62, startTime: 6.0, endTime: 6.5},
            {pitch: 62, startTime: 6.5, endTime: 7.0},
            {pitch: 60, startTime: 7.0, endTime: 8.0},
          ]
        }

        try {          
            const quantizedSequence = mm.sequences.quantizeNoteSequence(sequence, 1)
            var midi_bytes_array = mm.sequenceProtoToMidi(quantizedSequence)
            saveByteArray("test_with_quantized_sequence.midi", midi_bytes_array);
        
          } catch (error) {
            console.error(error)
        }

         function saveByteArray(reportName, byte) {
            var blob = new Blob([byte], {type: "audio/midi"});
            var link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            var fileName = reportName;
            link.download = fileName;
            link.click();
        };
    </script>

</body>
</html>

Thank you very much for your help.
Kind regards,

@Jars-of-jam-Scheduler Jars-of-jam-Scheduler changed the title sequenceProtoToMidi used on a quantizedSequence generates a MIDI file without song sequenceProtoToMidi used on a quantizedSequence generates a MIDI file without song (perhaps: unquantizeSequence is bugging) Jun 7, 2020
@notwaldorf
Copy link
Collaborator

notwaldorf commented Jun 7, 2020 via email

@Jars-of-jam-Scheduler
Copy link
Author

Jars-of-jam-Scheduler commented Jun 8, 2020

You are right. I solved this issue by adding "velocity: 100". However, I have the same problem with the following code (I try to output in a MIDI file a music generated by using MusicRNN):

const quantizedSequence = mm.sequences.quantizeNoteSequence(sequence, 1)
const improvisedMelody = await music_rnn.continueSequence(quantizedSequence, 20, 0.1, ['Bm'])
const midi_bytes_array = mm.sequenceProtoToMidi(improvisedMelody)

So, in this case, how could I specify a velocity for the notes of the improvisedMelody constant?
Indeed, your function continueSequence doesn't seem to specify a velocity.

@notwaldorf
Copy link
Collaborator

Right, I think MusicRNN also outputs this incorrectly with no velocities (see #448), so you'd have to do it after the fact. Something like:

improvisedMelody.notes.forEach(n => n.velocity = 100)

@Jars-of-jam-Scheduler
Copy link
Author

@notwaldorf Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants