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
C++ library for audio and music analysis, description and synthesis, including Python bindings

Essentia Essentia is an open-source C++ library for audio analysis and audio-based music information retrieval released under the Affero GPL license.

Music Technology Group - Universitat Pompeu Fabra 2.3k Jan 3, 2023
Python library for audio and music analysis

librosa A python package for music and audio analysis. Documentation See https://librosa.org/doc/ for a complete reference manual and introductory tut

librosa 5.6k Jan 6, 2023
Python Audio Analysis Library: Feature Extraction, Classification, Segmentation and Applications

A Python library for audio feature extraction, classification, segmentation and applications This doc contains general info. Click here for the comple

Theodoros Giannakopoulos 5.1k Jan 2, 2023
Python Audio Analysis Library: Feature Extraction, Classification, Segmentation and Applications

A Python library for audio feature extraction, classification, segmentation and applications This doc contains general info. Click here for the comple

Theodoros Giannakopoulos 3.8k Feb 17, 2021
Python audio and music signal processing library

madmom Madmom is an audio signal processing library written in Python with a strong focus on music information retrieval (MIR) tasks. The library is i

Institute of Computational Perception 1k Dec 26, 2022
A Python library and tools AUCTUS A6 based radios.

A Python library and tools AUCTUS A6 based radios.

Jonathan Hart 6 Nov 23, 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 7, 2023
cross-library (GStreamer + Core Audio + MAD + FFmpeg) audio decoding for Python

audioread Decode audio files using whichever backend is available. The library currently supports: Gstreamer via PyGObject. Core Audio on Mac OS X via

beetbox 419 Dec 26, 2022
cross-library (GStreamer + Core Audio + MAD + FFmpeg) audio decoding for Python

audioread Decode audio files using whichever backend is available. The library currently supports: Gstreamer via PyGObject. Core Audio on Mac OS X via

beetbox 359 Feb 15, 2021
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
A Python library for audio data augmentation. Inspired by albumentations. Useful for machine learning.

Audiomentations A Python library for audio data augmentation. Inspired by albumentations. Useful for deep learning. Runs on CPU. Supports mono audio a

Iver Jordal 1.2k Jan 7, 2023
pedalboard is a Python library for adding effects to audio.

pedalboard is a Python library for adding effects to audio. It supports a number of common audio effects out of the box, and also allows the use of VST3® and Audio Unit plugin formats for third-party effects.

Spotify 3.9k Jan 2, 2023
Generating a structured library of .wav samples with Python.

sample-library Scripts for generating a structured sample library with Python Requires Docker about Samples are written to wave files in lib/. Differe

Ben Mangold 1 Nov 11, 2021
Library for Python 3 to communicate with the Google Chromecast.

pychromecast Library for Python 3.6+ to communicate with the Google Chromecast. It currently supports: Auto discovering connected Chromecasts on the n

Home Assistant Libraries 2.4k Jan 2, 2023
music library manager and MusicBrainz tagger

beets Beets is the media library management system for obsessive music geeks. The purpose of beets is to get your music collection right once and for

beetbox 11.3k Dec 31, 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 4, 2023
:speech_balloon: SpeechPy - A Library for Speech Processing and Recognition: http://speechpy.readthedocs.io/en/latest/

SpeechPy Official Project Documentation Table of Contents Documentation Which Python versions are supported Citation How to Install? Local Installatio

Amirsina Torfi 870 Dec 27, 2022
a library for audio and music analysis

aubio aubio is a library to label music and sounds. It listens to audio signals and attempts to detect events. For instance, when a drum is hit, at wh

aubio 2.9k Dec 30, 2022
DCL - An easy to use diacritic library used for diacritic and accent manipulation.

Diacritics Library This library is used for adding, and removing diacritics from strings. Getting started Start by importing the module: import dcl DC

Kreus Amredes 6 Jun 3, 2022