SMF_GD.write(smf_data) returns 0 size PoolByteArray

Issue #59 resolved
1234ab created an issue

Hi! I’m trying to save a MIDI file, but I have a problem:

print(smf_data)
var bytes: PoolByteArray = SMF_GD.write(smf_data)
print(len(bytes))

And this prints:

{format_type:0, timebase:22, track_count:1, tracks:[{events:[{bpm:2000, channel_number:0, time:0, type:13}, {channel_number:0, note:43, time:148, type:1, velocity:127}, {channel_number:0, note:43, time:162, type:0, velocity:0}, {channel_number:0, note:44, time:101, type:1, velocity:123}, {channel_number:0, note:44, time:114, type:0, velocity:0}, {channel_number:0, note:46, time:70, type:1, velocity:127}, {channel_number:0, note:46, time:81, type:0, velocity:0}, {channel_number:0, note:50, time:165, type:1, velocity:127}, {channel_number:0, note:50, time:176, type:0, velocity:0}, {channel_number:0, note:51, time:52, type:1, velocity:127}, {channel_number:0, note:51, time:68, type:0, velocity:0}, {channel_number:0, note:51, time:81, type:1, velocity:127}, {channel_number:0, note:51, time:96, type:0, velocity:0}, {channel_number:0, note:51, time:117, type:1, velocity:127}, {channel_number:0, note:51, time:138, type:0, velocity:0}, {channel_number:0, note:55, time:5, type:1, velocity:90}, {channel_number:0, note:55, time:15, type:0, velocity:0}, {channel_number:0, note:55, time:21, type:1, velocity:127}, {channel_number:0, note:55, time:43, type:0, velocity:0}, {channel_number:0, note:59, time:175, type:1, velocity:127}, {channel_number:0, note:59, time:192, type:0, velocity:0}, {channel_number:0, time:195, type:12}], track_number:1}]}
0

So I’m using a dictionary, but the returned PoolByteArray is empty.

I’m setting the tempo, adding some notes, and then adding a track end event. (I saw that I don’t need to sort the events, it’s done internally)

I’m using Godot 3.2.4.rc5, but I tried with 3.2.3 once and that yielded a similar result.

(also, as a side note the wiki about https://bitbucket.org/arlez80/godot-midi-player/wiki/struct/SMF seems to be wrong, because it says I’d need to create a note on with something like this: {channel_number:0, time:175, event: {note:59, type:1, velocity:127}}, but it seems to work with this: {channel_number:0, note:59, time:175, type:1, velocity:127} and the previous one throws an error)

Can you/someone please help, what’s going on? Here’s a minimal reproduction project, with godot 3.2.3 this time:

Comments (8)

  1. 1234ab reporter

    Also, I’m not sure what that means but buf.get_available_bytes( ) are 0 at SMF.gd line 680 in function _write_track , and also stream.get_available_bytes() is 0 at line 574 in function write, just before returning the PoolArray. I don’t know though if that’s normal or not.

    I also tried printing out the note values of the note on events from _write_track and those seemed to be understood correctly.

    I’ll attach a minimal reproduction project.

  2. きのもと結衣 repo owner

    I fixed at 8aa7a41.

    You needs uses data structure that same as reader.

    sample:

    var smf_rw: = SMF_GD.new()
    var src = smf_rw.read_file("res://src.mid")
    var dest = smf_rw.write( src )
    var f: = File.new( )
    f.open( "write-test.mid", File.WRITE )
    f.store_buffer( dest )
    f.close( )
    

  3. 1234ab reporter

    Thanks a lot! With the help of midicsv and with the new commit, I was able to recreate what I wanted.

    So if someone from the future is reading this, here’s (a smaller part of) the example with dictionaries I wrote earlier that actually works, it should create a 65B large, 4s long midi file, playing 4 notes, in probably the easiest way possible:

    var SMF_GD = preload("res://addons/midi/SMF.gd").new()
    
    func _ready():
        var smf_data = {"format_type":1, "timebase":22, "track_count":1, "tracks":[{"track_number":1, "events":[
                {"channel_number":0, "time":0, "event": {"type":SMF_GD.MIDIEventType.system_event, "args":
                    {"bpm":500000, "type":SMF_GD.MIDISystemEventType.set_tempo}}}, 
                {"channel_number":0, "time":148, "event": {"note":43, "type":SMF_GD.MIDIEventType.note_on, "velocity":127}}, 
                {"channel_number":0, "time":162, "event": {"note":43, "type":SMF_GD.MIDIEventType.note_off, "velocity":0}}, 
                {"channel_number":0, "time":101, "event": {"note":44, "type":SMF_GD.MIDIEventType.note_on, "velocity":123}}, 
                {"channel_number":0, "time":114, "event": {"note":44, "type":SMF_GD.MIDIEventType.note_off, "velocity":0}}, 
                {"channel_number":0, "time":70, "event": {"note":46, "type":SMF_GD.MIDIEventType.note_on, "velocity":127}}, 
                {"channel_number":0, "time":81, "event": {"note":46, "type":SMF_GD.MIDIEventType.note_off, "velocity":0}}, 
                {"channel_number":0, "time":165, "event": {"note":50, "type":SMF_GD.MIDIEventType.note_on, "velocity":127}}, 
                {"channel_number":0, "time":176, "event": {"note":50, "type":SMF_GD.MIDIEventType.note_off, "velocity":0}}, 
                {"channel_number":0, "time":195, "event": {"type":SMF_GD.MIDIEventType.system_event, "args":
                    {"type":SMF_GD.MIDISystemEventType.end_of_track}}}, 
            ]}]}
        var bytes = SMF_GD.write(smf_data)
        var file = File.new()
        file.open("res://test.mid", File.WRITE)
        file.store_buffer(bytes)
        file.close()
    

    Analyzing the output with midicsv, there seem to be some random note_off events when the end_of_track event is missing, so don’t leave that out.

    of course you can organize it better, move type to the front, make more line breaks etc.

    Timebase is the “the number of clock pulses per quarter note“ where clock pulse is the same as the “time” value

    and set_tempo’s bpm is “The tempo is specified as the Number of microseconds per quarter note, between 1 and 16777215. A value of 500000 corresponds to 120 quarter notes (“beats”) per minute. To convert beats per minute to a Tempo value, take the quotient from dividing 60,000,000 by the beats per minute.”

    source: https://www.fourmilab.ch/webtools/midicsv/

    So I think we can close this, everything works.

  4. Log in to comment