A Python port and library-fication of the midicsv tool by John Walker.

Overview

py_midicsv

CircleCI Downloads

A Python library inspired by the midicsv tool created by John Walker. Its main purpose is to bidirectionally convert between the binary MIDI format and a human-readable interpretation of the contained data in text format, expressed as CSV. If you found this library, you probably already know why you need it.

Installation

py_midicsv can be installed via pip:

$ pip install py_midicsv

Alternatively you can build the package by cloning this repository and installing via poetry:

$ git clone https://github.com/timwedde/py_midicsv.git
$ cd py_midicsv/
$ poetry install

Usage

As a Command Line Tool

Usage: midicsvpy [OPTIONS] INPUT_FILE OUTPUT_FILE

  Convert MIDI files to CSV files.

  midicsv reads a standard MIDI file and decodes it into a CSV file which
  preserves all the information in the MIDI file. The ASCII CSV file may be
  loaded into a spreadsheet or database application, or processed by a
  program to transform the MIDI data (for example, to key transpose a
  composition or extract a track from a multi-track sequence). A CSV file in
  the format created by midicsv may be converted back into a standard MIDI
  file with the csvmidi program.

  Specify an input file and an output file to process it. Either argument
  can be stdin/stdout.

Options:
  -u, --usage
  -v, --verbose
  --help         Show this message and exit.
Usage: csvmidipy [OPTIONS] INPUT_FILE OUTPUT_FILE

  Convert CSV files to MIDI files.

  csvmidi reads a CSV file in the format written by midicsv and creates the
  equivalent standard MIDI file.

  Specify an input file and an output file to process it. Either argument
  can be stdin/stdout.

Options:
  -u, --usage
  -v, --verbose
  -z, --strict-csv
  -x, --no-compress
  --help             Show this message and exit.

As a Library

import py_midicsv as pm

# Load the MIDI file and parse it into CSV format
csv_string = pm.midi_to_csv("example.mid")

with open("example_converted.csv", "w") as f:
    f.writelines(csv_string)

# Parse the CSV output of the previous command back into a MIDI file
midi_object = pm.csv_to_midi(csv_string)

# Save the parsed MIDI file to disk
with open("example_converted.mid", "wb") as output_file:
    midi_writer = pm.FileWriter(output_file)
    midi_writer.write(midi_object)

Documentation

A full explanation of the midicsv file format can be found here.

Differences

This library adheres as much as possible to how the original library works, however generated files are not guaranteed to be entirely identical when compared bit-by-bit. This is mostly due to the handling of meta-event data, especially lyric events, since the encoding scheme has changed. The original library did not encode some of the characters in the Latin-1 set, while this version does.

Comments
  • Unexpected status byte 0x80 and Warning: Unknown Meta MIDI Event: 10

    Unexpected status byte 0x80 and Warning: Unknown Meta MIDI Event: 10

    File "midiToText.py", line 10, in convertMidiFile csv_string = pm.midi_to_csv(midiName) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midicsv.py", line 22, in parse pattern = read_midifile(file) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 221, in read_midifile return read_midifile(inp) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 223, in read_midifile return reader.read(midifile) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 45, in read self.parse_track(midifile, track) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 87, in parse_track event = self.parse_midi_event(trackdata) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 133, in parse_midi_event data = [trackdata.get_data_byte() for _ in range(cls.length)] File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 133, in <listcomp> data = [trackdata.get_data_byte() for _ in range(cls.length)] File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 36, in get_data_byte self.assert_data_byte(byte) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 29, in assert_data_byte assert data & 0x80 == 0, self.errmsg("Unexpected status byte", data) AssertionError: Unexpected status byte 0x80 at position 35078

    https://easyupload.io/zz2wf6 midi file that causes the issue

    when i comment out the assert the conversion passes, though i get a different error later with a different midi

    Traceback (most recent call last): File "midiToText.py", line 35, in <module> convertMidiFolderOfFolders(midiName) File "midiToText.py", line 20, in convertMidiFolderOfFolders convertMidiFolder(path + "/" + midiName) File "midiToText.py", line 16, in convertMidiFolder convertMidiFile(path + "/" + midiName) File "midiToText.py", line 10, in convertMidiFile csv_string = pm.midi_to_csv(midiName) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midicsv.py", line 22, in parse pattern = read_midifile(file) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 221, in read_midifile return read_midifile(inp) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 223, in read_midifile return reader.read(midifile) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 45, in read self.parse_track(midifile, track) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 87, in parse_track event = self.parse_midi_event(trackdata) File "/home/user/anaconda3/lib/python3.8/site-packages/py_midicsv/midi/fileio.py", line 103, in parse_midi_event raise Warning("Unknown Meta MIDI Event: " + repr(cmd)) Warning: Unknown Meta MIDI Event: 10 https://easyupload.io/8y3mz2

    file that causes the issue

    opened by Blizzsuxx 6
  • name conflict

    name conflict

    you should rename the command line midicsv and csvmidi scripts that you included. When I did the pip install, it overwrote my existing binaries from John Walker that were already located in /user/local/bin...

    Secondly, if you're going to overwrite, then the pip installer should prompt me to make sure that is what I really want to do

    thirdly, you should try to make your version of midicsv and csvmidi use the same command line options as the original binary so that if for some reason it does get overwritten and maybe I would even prefer to use your version for the Latin decoding...but if I have other scripts elsewhere based on using the binary midicsv, I don't want to break all those scripts.

    opened by steveschow 4
  • Not enough values on to_TimeSignatureEvent

    Not enough values on to_TimeSignatureEvent

    Hello and thank you for this great library! I am using it to do some processing on midi files, but I am having an issue with the TimeSignature of certain midi files.

    Making a csv csv_string = py_midicsv.midi_to_csv(source) gives me the line 1, 0, Time_signature, 4, 2. Then when I try to parse it back to midi (without any processing) midi = py_midicsv.csv_to_midi(csv_string) I get the following error:

    File ".../py_midicsv/csvmidi.py", line 46, in parse
        event = csv_to_midi_map[identifier](tr, time, identifier, line[3:])
    File ".../py_midicsv/csv_converters.py", line 142, in to_TimeSignatureEvent
        num, denom, click, notesq = map(int, line)
    ValueError: not enough values to unpack (expected 4, got 2)
    

    Is this a known issue and how can I prevent it?

    opened by SaschaVanEssen 3
  • Don't work

    Don't work

    in https://pypi.org/project/py-midicsv/#description

    we have

    import py_midicsv
    
    # Load the MIDI file and parse it into CSV format
    csv_string = py_midicsv.midi_to_csv("example.mid")
    
    # Parse the CSV output of the previous command back into a MIDI file
    midi_object = py_midicsv.csv_to_midi(csv_string)
    
    # Save the parsed MIDI file to disk
    with open("example_converted.mid", "wb") as output_file:
        midi_writer = py_midicsv.FileWriter(output_file)
        midi_writer.write(midi_object)
    

    in https://github.com/timwedde/py_midicsv

    we have

    import py_midicsv as pm
    
    # Load the MIDI file and parse it into CSV format
    csv_string = pm.midi_to_csv("example.mid")
    
    # Parse the CSV output of the previous command back into a MIDI file
    midi_object = pm.csv_to_midi(csv_string)
    
    # Save the parsed MIDI file to disk
    with open("example_converted.mid", "wb") as output_file:
        midi_writer = pm.FileWriter(output_file)
        midi_writer.write(midi_object)
    

    but none of them work or i did something wrong

    Traceback (most recent call last):
      File "C:/Users/felipe/PycharmProjects/2020/PORRA.py", line 9, in <module>
        midi_writer.write(midi_object)
    NameError: name 'midi_object' is not defined
    
    opened by npeeth 3
  • IndexError while Parsing MIDI

    IndexError while Parsing MIDI

    First of all, congrats for this Python library, which makes easier and integrable the parsing from MIDI files to CSV in Python. I'm encountering a problem while parsing a certain file, which gives the following error:

    Traceback (most recent call last): File "/Users/josepdecidrodriguez/Google Drive/IU/AML/Project/BachPropagation/src/dataset/parser.py", line 27, in data = py_midicsv.midi_to_csv(file) File "/Users/josepdecidrodriguez/Envs/BachPropagation-L4F7V3ER/lib/python3.7/site-packages/py_midicsv/midicsv.py", line 31, in parse csv_file.append(midi_to_csv_map[type(event)](index + 1, abstime, event)) File "/Users/josepdecidrodriguez/Envs/BachPropagation-L4F7V3ER/lib/python3.7/site-packages/py_midicsv/midi_converters.py", line 117, in from_KeySignatureEvent return write_event(track, time, "Key_signature", [event.get_alternatives(), '"major"' if event.data[1] == 0 else '"minor"']) IndexError: list index out of range

    This is given by the following file BWV_809____piano.txt (I've changed the extension to .txt to be able to upload it here).

    opened by josepdecid 3
  • several small fixes, to prevent crashes or unintended changes

    several small fixes, to prevent crashes or unintended changes

    The commits in this pull request together enable the package to read in any(?) valid midi file, convert it to CSV, and convert the CSV back to midi, without losing any data (or introducing any other changes). This was "almost" true already; most of the changes are small adjustments for particular event types.

    My test set of almost 5000 midi files inadvertently contained an invalid file, which (at first) the package happily translated to CSV and (almost) back to the original, without indicating a problem. The "Validate byte types in midi input" commit makes the package catch the bad file and report the place in the input where the problem was found. (Big points to Python's design for enabling that to be implemented cleanly!)

    See the commit comments for more details on the individual changes.

    opened by snively 2
  • Removing track from midi file

    Removing track from midi file

    Hi timwedde. I'm trying to build a dataset of midi-files for use in a machine learning project. I've been using py_midicsv to try and remove the drum track from my files. I've tried looking for "Program_c, 9" in the file after conversion to CSV, deleting that whole section and converting back to MIDI, but something is breaking. Could you maybe suggest a better way to do this? Thanks for the cool module!

    opened by aesthese 2
  • Processing folder? Why not? :)

    Processing folder? Why not? :)

    Tree project

    ├── csv
    │   └── AllBlues.csv
    ├── mid
    │   └── AllBlues.mid
    ├── midi
    │   └── AllBlues.mid
    

    Implementation

    import os
    import py_midicsv as pm
    
    #MIDI folder
    file_list=os.listdir(r"midi")
    
    #Custom Path
    path = ''
    
    #Create folders where to save files
    try:
        os.mkdir(path +"csv")
        os.mkdir(path +"mid") 
    
    except OSError:
        print ("Creation of the directory %s failed" % path)
    else:
        print ("Successfully created the directory %s" % path)
        
    for file_name_song in file_list:
        
        name_file_without_ext = file_name_song.rsplit('.', 1)[0]
        
        # Load the MIDI file and parse it into CSV format
        csv_string = pm.midi_to_csv("midi/"+ name_file_without_ext + ".mid")
    
        with open("csv/" + name_file_without_ext + ".csv", "w") as f:
            f.writelines(csv_string)
    
        # Parse the CSV output of the previous command back into a MIDI file
        midi_object = pm.csv_to_midi(csv_string)
    
        # Save the parsed MIDI file to disk
        with open("mid/" + name_file_without_ext + ".mid", "wb") as output_file:
            midi_writer = pm.FileWriter(output_file)
            midi_writer.write(midi_object)
        print("processed file name:",file_name_song)
    
    opened by Midnight93 1
  • Fix example of writing CSV string to file

    Fix example of writing CSV string to file

    As you mention here, the midi_to_csv function returns a list of strings. write is expecting a string rather than a list of strings, so running the example results in an error. Your provided fix was to use the writelines function instead, but you forgot to update the README.

    opened by joshnatis 1
  • TypeError: ('Bad header in MIDI file.', b'')

    TypeError: ('Bad header in MIDI file.', b'')

    Ran this on Google Colab, I uploaded a midi file and tested multiple and kept getting this error. What's going on? (Also, IDK why the indentations arent working on the code) ` #MIDI TO CSV

    import py_midicsv as pm def midi2csv(): save=input('filename\n') print("Step 1") owo=open(save,mode='w') print("Step 2") owo.write(str(pm.midi_to_csv(str(save)+'.mid'))) print("Step 3") owo.close print("Step 4") messagebox.showinfo('Complete','file saved as {}'.format(save)) print("Step 5") while 1==1: x=input('midi to CSV: 0\nend: 2\n') if x == '0': midi2csv() elif x == '2': break `

    opened by ExodusSolis 1
  • Add path option in csv2midi

    Add path option in csv2midi

    When converting CSV to MIDI, csv.reader requires a file object. I added the option to pass a file path that can be activated with an extra boolean parameter in order to not break current version behaviour.

    opened by josepdecid 1
Releases(v1.14.1)
Owner
Tim Wedde
I largely build solutions for odd problems you didn't know you had.
Tim Wedde
Klangbecken: The RaBe Endless Music Player

Klangbecken Klangbecken is the minimalistic endless music player for Radio Bern RaBe based on liquidsoap. It supports configurable and editable playli

Radio Bern RaBe 8 Oct 09, 2021
Anaphones are like anagrams, but for sounds.

Anaphones Anaphones are like anagrams but for sounds (phonemes). Examples include: salami-awesomely, atari-tiara, and beefy-phoebe. Anaphones can be a

James Murphy 18 Nov 02, 2022
Make an audio file (really) long-winded

longwind Make an audio file (really) long-winded Daily repetitions are an illusion anyway.

Vincent Lostanlen 2 Sep 12, 2022
This library provides common speech features for ASR including MFCCs and filterbank energies.

python_speech_features This library provides common speech features for ASR including MFCCs and filterbank energies. If you are not sure what MFCCs ar

James Lyons 2.2k Jan 04, 2023
Improved Python UI to convert Youtube URL to .mp3 file.

YT-MP3 Improved Python UI to convert Youtube URL to .mp3 file. How to use? Just run python3 main.py Enter the URL of the video Enter the PATH of where

8 Jun 19, 2022
Audio processor to map oracle notes in the VoG raid in Destiny 2 to call outs.

vog_oracles Audio processor to map oracle notes in the VoG raid in Destiny 2 to call outs. Huge thanks to mzucker on GitHub for the note detection cod

19 Sep 29, 2022
PianoPlayer - Automatic fingering generator for piano scores

PianoPlayer - Automatic fingering generator for piano scores

Marco Musy 571 Jan 02, 2023
Audio book player for senior visually impaired.

PI Zero W Audio Book Motivation and requirements My dad is practically blind and at 80 years has trouble hearing and operating tiny or more complicate

Andrej Hosna 29 Dec 25, 2022
Real-time audio visualizations (spectrum, spectrogram, etc.)

Friture Friture is an application to visualize and analyze live audio data in real-time. Friture displays audio data in several widgets, such as a sco

Timothée Lecomte 700 Dec 31, 2022
A python program to cut longer MP3 files (i.e. recordings of several songs) into the individual tracks.

I'm writing a python script to cut longer MP3 files (i.e. recordings of several songs) into the individual tracks called ReCut. So far there are two

Dönerspiess 1 Oct 27, 2021
PyAbsorp is a python module that has the main focus to help estimate the Sound Absorption Coefficient.

This is a package developed to be use to find the Sound Absorption Coefficient through some implemented models, like Biot-Allard, Johnson-Champoux and

Michael Markus Ackermann 8 Oct 19, 2022
Extract the songs from your osu! libary into proper mp3 form, complete with metadata and album art!

osu-Extract Extract the songs from your osu! libary into proper mp3 form, complete with metadata and album art! Requirements python3 mutagen pillow Us

William Carter 2 Mar 09, 2022
An audio digital processing toolbox based on a workflow/pipeline principle

AudioTK Audio ToolKit is a set of audio filters. It helps assembling workflows for specific audio processing workloads. The audio workflow is split in

Matthieu Brucher 238 Oct 18, 2022
Music player and music library manager for Linux, Windows, and macOS

Ex Falso / Quod Libet - A Music Library / Editor / Player Quod Libet is a music management program. It provides several different ways to view your au

Quod Libet 1.2k Jan 07, 2023
convert-to-opus-cli is a Python CLI program for converting audio files to opus audio format.

convert-to-opus-cli convert-to-opus-cli is a Python CLI program for converting audio files to opus audio format. Installation Must have installed ffmp

4 Dec 21, 2022
Python library for handling audio datasets.

AUDIOMATE Audiomate is a library for easy access to audio datasets. It provides the datastructures for accessing/loading different datasets in a gener

Matthias 121 Nov 27, 2022
Telegram Voice-Chat Bot Written In Python Using Pyrogram.

Telegram Voice-Chat Bot Telegram Voice-Chat Bot To Play Music From Various Sources In Your Group Support All linux based os. Windows Mac Diagram Requi

TheHamkerCat 314 Dec 29, 2022
IDing the songs played on the do you radio show

IDing the songs played on the do you radio show

Rasmus Jones 36 Nov 15, 2022
A Youtube audio player for your terminal

AudioLine A lightweight Youtube audio player for your terminal Explore the docs » View Demo · Report Bug · Request Feature · Send a Pull Request About

Haseeb Khalid 26 Jan 04, 2023
An AI for Music Generation

An AI for Music Generation

Hao-Wen Dong 1.3k Dec 31, 2022