{"id":30206202,"url":"https://github.com/jimm/midilib","last_synced_at":"2025-08-13T14:29:40.804Z","repository":{"id":463908,"uuid":"88420","full_name":"jimm/midilib","owner":"jimm","description":"Pure Ruby MIDI file and event manipulation library","archived":false,"fork":false,"pushed_at":"2025-07-15T14:48:50.000Z","size":276,"stargazers_count":183,"open_issues_count":2,"forks_count":35,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-07-28T03:47:29.334Z","etag":null,"topics":["midi","midi-api","midi-files","midi-parser","ruby"],"latest_commit_sha":null,"homepage":"https://github.com/jimm/midilib","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jimm.png","metadata":{"files":{"readme":"README.rdoc","changelog":"ChangeLog","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2008-12-10T20:50:26.000Z","updated_at":"2025-07-15T14:48:54.000Z","dependencies_parsed_at":"2024-01-15T01:04:50.053Z","dependency_job_id":"52a2537a-fbcc-4017-bfda-9e901502ba27","html_url":"https://github.com/jimm/midilib","commit_stats":{"total_commits":133,"total_committers":12,"mean_commits":"11.083333333333334","dds":0.631578947368421,"last_synced_commit":"8edad88f2afec766be3ff5ddabd24008a8059ee8"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jimm/midilib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimm%2Fmidilib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimm%2Fmidilib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimm%2Fmidilib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimm%2Fmidilib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jimm","download_url":"https://codeload.github.com/jimm/midilib/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jimm%2Fmidilib/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270257085,"owners_count":24553543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-13T02:00:09.904Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["midi","midi-api","midi-files","midi-parser","ruby"],"created_at":"2025-08-13T14:29:35.277Z","updated_at":"2025-08-13T14:29:40.754Z","avatar_url":"https://github.com/jimm.png","language":"Ruby","readme":"= midilib\n\nmidilib is a pure Ruby MIDI library useful for reading and writing standard\nMIDI files and manipulating MIDI event data.\n\nThe GitHub project page and Web site of midilib is\nhttp://github.com/jimm/midilib and the RubyGems.org page is\nhttp://rubygems.org/gems/midilib, where you can also find all the RDoc\ndocumentation.\n\nmidilib is compatible with Ruby 2.6 and higher.\n\n\n== Dependencies\n\nmidilib does not require any other packages. The test suite in the tests\ndirectory requires the testing framework TestUnit, which comes with Ruby 1.8\nand later and can also be found in the Ruby Application Archive\n(http://raa.ruby-lang.org).\n\nTo rebuild the gem or RDocs or run the tests easily, you can use the Rakefile\nwhich requires Rake (http://rake.rubyforge.org).\n\n\n== Installation\n\n=== RubyGems Installation\n\nTo install midilib as a gem, type\n\n    % gem install midilib\nor, if you already have a previous version, use\n    % gem update midilib\n\nYou may need root privileges to install or update the gem.\n\n=== Manual Installation\n\nAfter downloading and expanding the archive, you can install midilib with the\ncommand\n\n    % ruby install.rb\n(or)\n    % ruby install.rb --install-dir=my_directory\n\nYou may need root privileges to install.\n\n\n== Testing\n\n  % rake test\n\nruns all of the tests in the test directory.\n\n\n== Overview\n\nmidilib can read and write MIDI file formats 0 (one single track) or 1\nmultiple tracks. By default, it writes format 1 which is the most common\nformat. MIDI file format 2 is not yet supported.\n\n=== MIDI::Sequence\n\nA sequence contains a collection of tracks and global information like the\nsequence's pulses per quarter note (ppqn) and time signature.\n\nThe first track in a sequence is special; it holds meta-events like tempo and\nsequence name. Don't put any notes in this track.\n\nMIDI::Sequence also contains some convenience methods that let you set and\nretrieve the sequence's name, the time signature, and to retrieve the first\ntempo event's beats-per-minute value.\n\nNormally instances of MIDI::IO::SeqReader and MIDI::IO::SeqWriter are used\nwhen a sequence reads itself from or writes itself to a MIDI file. You can\nchange that by setting a sequence's reader_class or writer_class attributes.\nInstances of the classes contained in those attributes are created and used\nwhenever the sequence reads or writes itself.\n\n=== MIDI::Track\n\nA track contains an array of events.\n\nWhen you modify the +events+ array, make sure to call recalc_times so each\nevent gets its +time_from_start+ recalculated. You don't have to do that\nafter every event you add; just remember to do so before using the track in a\nway that expects the list of events to be ordered correctly.\n\nA Track also holds a bit mask that specifies the channels used by the track.\nThis bit mask is set when the track is read from the MIDI file by a SeqReader\nbut is _not_ kept up to date by any other methods. Specifically, if you add\nevents to a track at any other time, the bit mask will not be updated.\n\nWhen a Track is read from a MIDI file, a MIDI::META_TRACK_END event is added\nto the end if there isn't one in the file already. When a Track is written\nto a MIDI file, a MIDI::META_TRACK_END event is always output even if the\nTrack does not have one.\n\nThe Track#merge method ensures that there is only one MIDI::META_TRACK_END\nevent after the merge and that it's at its proper place at the end of the\nlist of events. It does so by calling Track#ensure_track_end_meta_event.\n\n=== MIDI::Measure\n\nThis class contains information about a measure from the sequence. Measure\ndata is based on the time signature information from the sequence and is not\nstored in the sequence itself.\n\n=== MIDI::Measures\n\nThe class MIDI::Sequence method get_measures returns a MIDI::Measures object.\nMIDI::Measures is a subclass of Array. It is a specialized container for\nMIDI::Measure objects, which can be use to map event times to measure numbers.\nPlease note that this object has to be remade when events are deleted/added in\nthe sequence.\n\nMIDI::Measure and MIDI::Measures are brought to us by Jari Williamsson\n\u003cjari.williamsson@mailbox.swipnet.se\u003e, who also contributed some improvements\nto the MIDI::Event and MIDI::Track classes.\n\n=== MIDI::Event\n\nEach event holds not only its delta time but also its time from the start of\nthe track. The track is responsible for recalculating its events' start times.\nYou can call MIDI::Track#recalc_times to do so.\n\nSubclasses of MIDI::Event implement the various MIDI messages such as note on\nand off, controller values, system exclusive data, and realtime bytes.\n\nMIDI::Realtime events have delta values and start times, just like all the\nother midilib event types do. (MIDI real time status bytes don't have delta\ntimes, but this way we can record when in a track the realtime byte was\nreceived and should be sent. This is useful for start/continue/stop events\nthat control other devices, for example.) Note that when a MIDI::Realtime\nevent is written out to a MIDI file, the delta time is not written.\n\nMIDI::MetaEvent events hold an array of bytes named 'data'. Many meta events\nare string holders (text, lyric, marker, etc.) Though the 'data' value is\nalways an array of bytes, MIDI::MetaEvent helps with saving and accessing\nstring. The MIDI::MetaEvent#data_as_str method returns the data bytes as a\nstring. When assigning to a meta event's data, if you pass in a string it will\nget converted to an array of bytes.\n\n\n== How To Use midilib\n\nThe following examples show you how to use midilib to read, write, and\nmanipulate MIDI files and modify track events. See also the files in the\nexamples directory, which are described below.\n\n\n=== Reading a MIDI File\n\nTo read a MIDI file, create a MIDI::Sequence object and call its #read method,\npassing in an IO object.\n\nThe #read method takes an optional block. If present, the block is called\nonce after each track has finished being read. Each time, it is passed the\ntrack object, the total number of tracks and the number of the current track\nthat has just been read. This is useful for notifying the user of progress,\nfor example by updating a GUI progress bar.\n\n require 'midilib/io/seqreader'\n\n # Create a new, empty sequence.\n seq = MIDI::Sequence.new()\n\n # Read the contents of a MIDI file into the sequence.\n File.open('my_midi_file.mid', 'rb') { | file |\n     seq.read(file) { | track, num_tracks, i |\n         # Print something when each track is read.\n         puts \"read track #{i} of #{num_tracks}\"\n     }\n }\n\n\n=== Writing a MIDI File\n\nTo write a MIDI file, call the write method, passing in an IO object.\n\n\n require 'midilib/io/seqwriter'\n\n # Start with a sequence that has something worth saving.\n seq = read_or_create_seq_we_care_not_how()\n\n # Write the sequence to a MIDI file.\n File.open('my_output_file.mid', 'wb') { | file | seq.write(file) }\n\n\n=== Editing a MIDI File\n\nCombining the last two examples, here is a script that reads a MIDI file,\ntransposes some events, and writes the sequence out to a different file. This\nis a useful template for programatically manipulating MIDI data.\n\n\nThis code transposes all of the note events (note on, note off, and poly\npressure) on channel 5 down one octave.\n\n==== Transposing One Channel\n\n require 'midilib/io/seqreader'\n require 'midilib/io/seqwriter'\n\n # Create a new, empty sequence.\n seq = MIDI::Sequence.new()\n\n # Read the contents of a MIDI file into the sequence.\n File.open('my_input_file.mid', 'rb') { | file |\n     seq.read(file) { | track, num_tracks, i |\n         # Print something when each track is read.\n         puts \"read track #{i} of #{num_tracks}\"\n     }\n }\n\n # Iterate over every event in every track.\n seq.each { | track |\n     track.each { | event |\n         # If the event is a note event (note on, note off, or poly\n         # pressure) and it is on MIDI channel 5 (channels start at\n         # 0, so we use 4), then transpose the event down one octave.\n         if MIDI::NoteEvent === event \u0026\u0026 event.channel == 4\n             event.note -= 12\n         end\n     }\n }\n\n # Write the sequence to a MIDI file.\n File.open('my_output_file.mid', 'wb') { | file | seq.write(file) }\n\n\n=== Manipulating tracks\n\nIf you modify a track's list of events directly, don't forget to call\nMIDI::Track#recalc_times when you are done.\n\n track.events[42, 1] = array_of_events\n track.events \u003c\u003c an_event\n track.merge(array_of_events)\n track.recalc_times\n\n=== Calculating delta times\n\nA few methods in MIDI::Sequence make it easier to calculate the delta times\nthat represent note lengths. MIDI::Sequence#length_to_delta takes a note\nlength (a multiple of a quarter note) and returns the delta time given the\nsequence's current ppqn (pulses per quarter note) setting. 1 is a quarter\nnote, 1.0/32.0 is a 32nd note (use floating-point numbers to avoid integer\nrounding), 1.5 is a dotted quarter, etc. See the documentation for that method\nfor more information.\n\nMIDI::Sequence#note_to_length takes a note name and returns a length value\n(again, as a multiple of a quarter note). Legal note names are those found in\nMIDI::Sequence::NOTE_TO_LENGTH, and may begin with \"dotted\" and/or end with\n\"triplet\". For example, \"whole\", \"sixteenth\", \"32nd\", \"quarter triplet\",\n\"dotted 16th\", and \"dotted 8th triplet\" are all legal note names.\n\nFinally, MIDI::Sequence#note_to_delta takes a note name and returns a delta\ntime. It does this by calling note_to_length, then passing the result to\nlength_to_delta.\n\n\n=== Example Scripts\n\nHere are short descriptions of each of the examples found in the examples\ndirectory.\n\n* examples/from_scratch.rb shows you how to create a new sequence from scratch\n  and save it to a MIDI file. It creates a file called 'from_scratch.mid'.\n\n* examples/seq2text.rb dumps a MIDI file as text. It reads in a sequence and\n  uses the to_s method of each event.\n\n* examples/reader2text.rb dumps a MIDI file as text. It subclasses\n  MIDI::SeqReader instead of creating a sequence containing tracks and events.\n\n* examples/transpose.rb transposes all note events (note on, note off, poly\n  pressure) on a specified channel by a specified amount.\n\n* There is also one MIDI file, examples/NoFences.mid. It is a little pop ditty\n  I wrote. The instruments in this file use General MIDI patch numbers and\n  drum note assignments. Since I don't normally use GM patches, the sounds\n  used here are at best approximations of the sounds I use.\n\n\n== Resources\n\nThe Ruby Web site (http://www.ruby-lang.org/en/index.html) contains an\nintroduction to Ruby, the Ruby Application Archive (RAA) at\nhttp://raa.ruby-lang.org, and pointers to more information.\n\n\n\u003ccite\u003eProgramming Ruby, The Pragmatic Programmer's Guide\u003c/cite\u003e, by David\nThomas and Andrew Hunt, is a well-written and practical introduction to Ruby.\nIts Web page at http://www.rubycentral.com/book also contains a wealth of Ruby\ninformation. Though the first edition book is available online, I encourage\nyou to purchase a copy of the latest edition.\n\nA description of the MIDI file format can be found in a few places such as\nhttps://www.csie.ntu.edu.tw/~r92092/ref/midi/.\n\nThe MIDI message reference at http://www.jimmenard.com/midi_ref.html\ndescribes the format of MIDI commands.\n\n\n= To Do\n\n:include: TODO.rdoc\n\n\n= Support\n\n* Visit the forums, bug list, and mailing list pages at\n  http://rubyforge.org/projects/midilib\n\n* Send email to Jim Menard at mailto:jim@jimmenard.com\n\n* Ask on the ruby-talk mailing list\n\n\n= Administrivia\n\nAuthor:: Jim Menard (mailto:jim@jimmenard.com)\nCopyright:: Copyright (c) 2003-2023 Jim Menard\nLicense:: Distributed under the same license as Ruby.\n\n\n== Copying\n\nmidilib is copyrighted free software by Jim Menard and is released under the\nsame license as Ruby. See the Ruby license at\nhttp://www.ruby-lang.org/en/LICENSE.txt.\n\nmidilib may be freely copied in its entirety providing this notice, all\nsource code, all documentation, and all other files are included.\n\nmidilib is Copyright (c) 2003-2023 by Jim Menard.\n\nThe song \"No Fences\" contained in the MIDI file examples/NoFences.mid is\nCopyright (c) 1992 by Jim Menard (jim@jimmenard.com). It may be freely used\nfor non-commercial purposes as long as the author is given credit.\n\n== Warranty\n\nThis software is provided \"as is\" and without any express or implied\nwarranties, including, without limitation, the implied warranties of\nmerchantability and fitness for a particular purpose.\n","funding_links":[],"categories":["Programming Languages"],"sub_categories":["Ruby"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimm%2Fmidilib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjimm%2Fmidilib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimm%2Fmidilib/lists"}