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
A library for augmenting annotated audio data

muda A library for Musical Data Augmentation. muda package implements annotation-aware musical data augmentation, as described in the muda paper. The

Brian McFee 214 Nov 22, 2022
In this project we can see how we can generate automatic music using character RNN.

Automatic Music Genaration Table of Contents Project Description Approach towards the problem Limitations Libraries Used Summary Applications Referenc

Pronay Ghosh 2 May 27, 2022
❤️ Hi There Im Cozmo Music Bot A next gen powerful telegram group Music bot for get your Songs and music @Venuja_Sadew

🎵 Cozmo MUSIC 🎵 Cozmo Music is a Music powerfull bot for playing music on telegram voice chat groups. Requirements FFmpeg NodeJS nodesource.com Pyth

Venuja Sadew 3 Jan 08, 2022
Scalable audio processing framework written in Python with a RESTful API

TimeSide : scalable audio processing framework and server written in Python TimeSide is a python framework enabling low and high level audio analysis,

Parisson 340 Jan 04, 2023
This is an AI that runs in the terminal. It is a voice assistant that can do common activities and can also help in your coding doubts like

This is an AI that runs in the terminal. It is a voice assistant that can do common activities and can also help in your coding doubts like

OneBit 1 Nov 05, 2021
The project aims to develop a personal-assistant for Windows & Linux-based systems

The project aims to develop a personal-assistant for Windows & Linux-based systems. Samiksha draws its inspiration from virtual assistants like Cortana for Windows, and Siri for iOS. It has been desi

SHUBHANSHU RAI 1 Jan 16, 2022
Real-Time Spherical Microphone Renderer for binaural reproduction in Python

ReTiSAR Implementation of the Real-Time Spherical Microphone Renderer for binaural reproduction in Python [1][2]. Contents: | Requirements | Setup | Q

Division of Applied Acoustics at Chalmers University of Technology 51 Dec 17, 2022
Okaeri-Music is a telegram music bot project, allow you to play music on voice chat group telegram.

Okaeri-Music is a telegram bot project that's allow you to play music on telegram voice chat group

Wahyusaputra 1 Dec 22, 2021
Speech recognition module for Python, supporting several engines and APIs, online and offline.

SpeechRecognition Library for performing speech recognition, with support for several engines and APIs, online and offline. Speech recognition engine/

Anthony Zhang 6.7k Jan 08, 2023
Expressive Digital Signal Processing (DSP) package for Python

AudioLazy Development Last release PyPI status Real-Time Expressive Digital Signal Processing (DSP) Package for Python! Laziness and object representa

Danilo de Jesus da Silva Bellini 642 Dec 26, 2022
Code for "Audio-driven Talking Face Video Generation with Learning-based Personalized Head Pose"

Audio-driven Talking Face Video Generation with Learning-based Personalized Head Pose We provide PyTorch implementations for our arxiv paper "Audio-dr

Ran Yi 497 Jan 09, 2023
Accompanying code for our paper "Point Cloud Audio Processing"

Point Cloud Audio Processing Krishna Subramani1, Paris Smaragdis1 1UIUC Paper For the necessary libraries/prerequisites, please use conda/anaconda to

Krishna Subramani 17 Nov 17, 2022
Code to work with wave files!

Code to work with wave files!

Mohammad Dori 3 Jul 15, 2022
Audio library for modelling loudness

Loudness Loudness is a C++ library with Python bindings for modelling perceived loudness. The library consists of processing modules which can be casc

Dominic Ward 33 Oct 02, 2022
Music Streaming Platform based on full implementation of DBSM

Symphony Music Streaming Platform based on full implementation of DBSM List of Commands Insert User (INSERT) Function to implement input in USER Get a

Parth Maradia 1 Nov 12, 2021
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
𝙰 𝙼𝚞𝚜𝚒𝚌 𝙱𝚘𝚝 𝙲𝚛𝚎𝚊𝚝𝚎𝚍 𝙱𝚢 𝚃𝚎𝚊𝚖𝙳𝚕𝚝 💖

TeamDltmusic 𝙰 𝙼𝚞𝚜𝚒𝚌 𝙱𝚘𝚝 𝙲𝚛𝚎𝚊𝚝𝚎𝚍 𝙱𝚢 𝚃𝚎𝚊𝚖𝙳𝚕𝚝 💖 Deploy String Session String Click hear you can find string session OR join He

TeamDlt 5 Jan 18, 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
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
A useful tool to generate chord progressions according to melody MIDIs

Auto chord generator, pure python package that generate chord progressions according to given melodies

Billy Yi 53 Dec 30, 2022