{ "info": { "author": "Julian Porter", "author_email": "julian@porternet.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Other Audience", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Multimedia :: Sound/Audio :: MIDI" ], "description": "MIDIFile\n========\n\nA simple Python3 MIDI File / stream parser / decoder\n\nIntroduction\n------------\n\nAPI\n---\nThe top-level namespace is **MIDI**, which contains two classese: **MIDI.MIDIFile** and **MIDI.Track**.\n\nClass **MIDI.MIDIFile**\n^^^^^^^^^^^^^^^^^^^^^^^\n\nRepresents a file of Standard Midi Format (SMF) data, as defined by the `MIDI Association`_. **MIDI.MIDIFile** objects are iterable and array-like.\n\nConstructor\n\"\"\"\"\"\"\"\"\"\"\"\n\n**MIDI.MIDIFile**.__init__(*self*, ``filename``)\n\n .. list-table::\n\n * - ``filename`` \n - the name of an SMF file to read and parse. Raises an exception if the file does not exist / cannot be read.\n\nMethods\n\"\"\"\"\"\"\"\n\n .. list-table::\n\n * - **MIDI.MIDIFile**.parse(*self*)\n - Parse the file. Determines the file's type and populates an array of content tracks, each of which contains one track from the file and is represented by a **MIDI.Track** instance.\n * - **MIDI.MIDIFile**.__len__(*self*)\n - The number of tracks in the file (0 if ``parse`` has not yet been invoked).\n * - **MIDI.MIDIFile**.__iter__(*self*) \n - Iterates over the tracks in the file\n * - **MIDI.MIDIFile**.__get_item__(*self*, ``n``)\n - A **MIDI.Track** object, representing the ``n``'th track in the file (or throws a **RangeError** if ``n`` is out of range)\n * - **MIDI.MIDIFile**.__str__(*self*)\n - Useful information about the file as a whole, number of tracks and their sizes\n\nProperties\n\"\"\"\"\"\"\"\"\"\"\n\nIf *self* is an **MIDI.MIDIFile** instance then\n\n .. list-table::\n\n * - *self*.format\n - int\n - The MIDI format of the loaded file. Possible values are `0`, `1` and `2` (or **None** if the ``parse`` method has not yet been invoked). See page 134 of the `MIDI Specification v1.0`_.\n * - *self*.division\n - uint16\n - Time quantum of the MIDI data encoded in the file (or ``None`` if the ``parse`` method has not yet been invoked). Interpretation depends on the value: \n\n - `< 32768` : equals number of ticks per quarter-note; often equal to ``960``\n - `>=32786` : number of subdivisions of a second as defined in the `SMTPE Standard`_ and on pages 116- of the `MIDI Specification v1.0`_. Equals `32768 + 256 f + t` where `f` identifies one of the standard MIDI time code formats, and signifies the number of frames per second, while `f` is the numbef of subdivisions within a frame (common values are `4`, `8`, `10`, `80` and `100`).\n\n\nClass **MIDI.Track**\n^^^^^^^^^^^^^^^^^^^^\nClass representing a single track from an SMF file, or a collection of MIDI events. **MIDI.Track** objects are iterable and array-like.\n\nConstructor\n\"\"\"\"\"\"\"\"\"\"\"\n\n**MIDI.Track**.__init__(*self*, ``data``, ``containsTiming = True``)\n\nArguments:\n\n\n .. list-table::\n\n * - ``data``\n - binary string or array \n - data comprising one track from an SMF file, or a sequence of MIDI messages\n * - ``containsTiming``\n - boolean\n - **True** if ``data`` consists of MIDI events interleaved with timestamps (as in an SMF file); **False** if it is a sequence of MIDI messages\n\n\nSo, for example\n\n .. code-block:: python\n\n track = Track(data,containsTiming=True)\n\n initialises ``track`` for parsing ``data`` representing a track taken from an SMF file; while\n\n .. code-block:: python\n\n track = Track(data,containsTiming=False)\n\n initialises ``track`` for parsing ``data`` consisting of a sequence of one or more raw MIDI events, e.g. captured from an observed MIDI stream, or sent to the application by a MIDI controller.\n\nMethods\n\"\"\"\"\"\"\"\n\n .. list-table::\n\n * - **MIDI.Track**.parse(*self*)\n - Parse the track into an array of events, ordered based on their appearance in the track. Events are represented by instances of **MIDI.Events.Event**.\n * - **MIDI.Track**.__len__(*self*)\n - Returns the number of messages in the track (0 if ``parse`` has not yet been invoked).\n * - **MIDI.Track**.__iter__(*self*)\n - Iterates over the events / messages in the track, in the order in which they appeared.\n * - **MIDI.Track**.__get_item__(*self*, ``n``)\n - Returns a **MIDI.Events.Event** instance representing the ``n``'th event in the track (or throws a **RangeError** if ``n`` is out of range).\n * - **MIDI.Track**.__str__(*self*)\n - Returns string representations of all the track's events, concatenated and separated by newline ``'\\n'``.\n\n\nClass **MIDI.Events.Event**\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRepresents a general event as found in SMF files, or streams of MIDI messages. Specific kinds of event are represented by subclasses (for which, see below).\n\nConstructor\n\"\"\"\"\"\"\"\"\"\"\"\n **MIDI.Events.Event**.__init__(*self*, ``time``, ``buffer``)\n\n Arguments:\n\n .. list-table::\n\n * - ``time`` \n - uint64 \n - MIDI timestamp for the time of the event's occurrence, relative to some arbitrary zero.\n * - ``buffer`` \n - binary string or array \n - bytes making up the event.\n\nMethods\n\"\"\"\"\"\"\"\n\n .. list-table::\n\n\n * - **MIDI.Events.Event**.__len__(*self*)\n - The total length of the event.\n * - **MIDI.Events.Event**.__str__(*self*)\n - String representation of the event. By default, a representation of the raw bytes as a binary string.\n\nProperties\n\"\"\"\"\"\"\"\"\"\"\n\nIf *self* is an **MIDI.Events.Event** instance then\n\n .. list-table::\n\n * - *self*.time\n - the timestamp with which the event instance was initialised; measured in units of the quantum of time defined by the value of the ``division`` property of the **MIDI.MIDIFile** instance containing the track of which this event forms a part.\n * - *self*.header\n - the event's initial byte, which serves to identify its kind.\n * - *self*.data\n - binary string or array containing the event's *body*, i.e. its data content, with the header byte and other formatting removed\n\nSpecialisations of this class, describing specific kinds of SMF event, offer various dynamically generated read-only properties, describing properties specific to them. This is described below: \n\n\n**Meta Events**\n\nProvide information about the track, e.g. lyrics, tempo, etc, are represented by the type **MIDI.Events.MetaEvent**, which has the following additional properties:\n\n\n .. list-table::\n\n * - ``ev.message`` \n - is the meta event's kind, expressed as a member of the enumeration **MIDI.Events.meta.MetaEventKinds** for defined message types (see pages 137-139 of the `MIDI Specification v1.0`_ for a complete list) , and **None** otherwise \n\nOther parameters exist only for specific event kinds as follows:\n\n\n .. list-table::\n :header-rows: 1\n\n * - Property\n - Description\n - Meta Event Type(s)\n * - ``ev.text`` \n - general text\n - Text, Copyright_Notice, Track_Name, Instrument_Name, Lyric, Marker, Cue_Point\n * - ``ev.number`` \n - sequence number\n - Sequence_Number\n * - ``ev.channel`` \n - channel number\n - MIDI_Channel_Prefix\n * - ``ev.tempo``\n - tempo\n - Set_Tempo\n * - ``ev.hh``\n - hours\n - SMTPE_Offset \n * - ``ev.mm``\n - minutes\n - SMTPE_Offset\n * - ``ev.ss``\n - seconds\n - SMTPE_Offset \n * - ``ev.frame``\n - frames\n - SMTPE_Offset \n * - ``ev.numerator`` \n - time signature top number\n - Time_Signature\n * - ``ev.denominator``\n - time signature bottom number\n - Time_Signature\n * - ``ev.clocksPerTick``\n - number of MIDI clocks per tick\n - Time_Signature\n * - ``ev.demisemiquaverPer24Clocks``\n - what it says\n - Time_Signature\n\n**System Events**\n\nTell MIDI instruments how to perform the track, and are represented by the type **MIDI.Events.SysExEvent**. Each System event consists of a single MIDI **System** message. If ``self`` is an instance of **MIDI.Events.SysExEvent** then:\n\n .. list-table::\n\n * - ``ev.type`` \n - uint8\n - is the MIDI system message's kind, expressed as an integer 0 - 15; it is equal to ``ev.header & 15``\n\n**MIDI Events**\n\nTell MIDI instruments what to play when performing the track, and are represented by the type **MIDI.Events.MIDIEvent**. All instances have the following fields:\n\n .. list-table::\n\n * - ``ev.command``\n - uint8\n - The message command type, as defined in the `MIDI Specification v1.0`_. Equal to ``ev.header & 240``\n * - ``ev.channel``\n - uint8\n - The channel that the message relates to. Equal to ``ev.header & 15``\n * - ``ev.message``\n - message type specific\n - Instance of a class representing this particular kind of MIDI message; depending on ``ev.command`` \n\nThe value of ``ev.message`` is as follows, depending on the message type:\n\n **NOTE-OFF** or **NOTE-ON** (``command = 0x80 or 0x90``)\n\n .. list-table::\n\n * - ``ev.onOff``\n - **ON** if this is a **NOTE-ON** message; **OFF** if it is a **NOTE-OFF** message\n * - ``ev.note``\n - The note to which the message refers\n * - ``ev.velocity``\n - The velocity with which the note is applied\n\n **KEY PRESSURE** (``command = 0xa0``)\n\n .. list-table::\n\n * - ``ev.note``\n - The note to which the message refers\n * - ``ev.pressure``\n - The pressure with which the note is applied\n\n **CONTROL CHANGE** (``command = 0xb0``)\n\n .. list-table::\n\n * - ``ev.command``\n - The control that should be changed; represented either as a named object, for known controls, or as an unsigned integer for others\n * - ``ev.pressure``\n - The new value of the control; converted to **ON** / **OFF**, etc for known controls, left as an unsigned integer for others\n\n **PROGRAM CHANGE** (``command = 0xc0``)\n\n .. list-table::\n\n * - ``ev.name``\n - always equal to **\"Program\"**\n * - ``ev.value``\n - The new program number\n\n **CHANNEL PRESSURE** (``command = 0xd0``)\n\n .. list-table::\n\n * - ``ev.name``\n - always equal to **\"Pressure\"**\n * - ``ev.value``\n - The new pressure value for the channel as an unsigned integer\n\n **PITCH BEND CHANGE** (``command = 0xe0``)\n\n .. list-table::\n\n * - ``ev.name``\n - always equal to **\"BEND\"**\n * - ``ev.value``\n - The new pitch bend for the channel as a signed integer `b` such that `-2048 <= b <= 2047`\n\n\n\n\n\n\n\n\nExamples\n--------\n\nIncluded in the package is the following simple test script:\n\n .. code-block:: python\n\n from MIDI import MIDIFile\n from sys import argv\n\n def parse(file):\n c=MIDIFile(file)\n c.parse()\n print(str(c))\n for idx, track in enumerate(c):\n track.parse()\n print(f'Track {idx}:')\n print(str(track))\n\n\n parse(argv[1]) \n\nThe first few lines of the output from applying this to a SMF file are as follows: ::\n\n Format 1 nTracks 4 division 960\n\t Track 0 of length 0\n\t Track 1 of length 0\n\t Track 2 of length 0\n\t Track 3 of length 0\n Track 0:\n META@0 Key Signature -> key=C mode=major\n META@0 Set Tempo -> tempo=128.57136\n META@0 Track Name -> text=b'It was a punter and a pro'\n META@0 Text -> text=b'Julian Porter'\n META@0 Copyright Notice -> text=b'Copyright \\xa9 Julian Porter'\n META@1 End Of Track -> \n Track 1:\n MIDI@6336 0[0] \n MIDI@6336 CONTROL_CHANGE[1] Pan := 16\n MIDI@6336 CONTROL_CHANGE[1] Channel Volume := 112\n META@6336 Track Name -> text=b'Soprano'\n META@10656 Lyric -> text=b'It '\n MIDI@10656 NOTE_ON[1] E5 ON velocity := 36\n MIDI@11136 NOTE_OFF[1] E5 OFF velocity := 0\n META@11136 Lyric -> text=b'was '\n MIDI@11136 NOTE_ON[1] G#5 ON velocity := 36\n MIDI@11616 NOTE_OFF[1] G#5 OFF velocity := 0\n META@11616 Lyric -> text=b'a '\n MIDI@11616 NOTE_ON[1] C6 ON velocity := 36\n MIDI@12096 NOTE_OFF[1] C6 OFF velocity := 0\n META@12096 Lyric -> text=b'pun'\n MIDI@12096 NOTE_ON[1] A#5 ON velocity := 36\n MIDI@12576 NOTE_OFF[1] A#5 OFF velocity := 0\n META@12576 Lyric -> text=b'ter '\n MIDI@12576 CONTROL_CHANGE[1] RPN MSB := 0\n MIDI@12576 CONTROL_CHANGE[1] RPN LSB := 0\n MIDI@12576 CONTROL_CHANGE[1] Data Entry MSB := 4\n MIDI@12576 CONTROL_CHANGE[1] Data Entry LSB := 0\n MIDI@12576 PITCH_BEND[1] Bend := -8192\n MIDI@12576 PITCH_BEND[1] Bend := 8191\n MIDI@12591 PITCH_BEND[1] Bend := 7927\n MIDI@12606 PITCH_BEND[1] Bend := 7663\n MIDI@12621 PITCH_BEND[1] Bend := 7399\n MIDI@12636 PITCH_BEND[1] Bend := 7134\n MIDI@12651 PITCH_BEND[1] Bend := 6870\n MIDI@12651 NOTE_ON[1] C#6 ON velocity := 36\n MIDI@12666 PITCH_BEND[1] Bend := 6606\n MIDI@12681 PITCH_BEND[1] Bend := 6342\n MIDI@12696 PITCH_BEND[1] Bend := 6077\n MIDI@12711 PITCH_BEND[1] Bend := 5813\n\nThis clearly shows the overall structure of the file (with four tracks), the content of the initial metadata track, which specifies tempo, key, etc, and the start of the second track, which mixes MIDI messages specifying what an instrument should play, with metadata providing lyrics, etc. \n\n\nRequirements\n------------\n\nMIDIFile is a pure python module requiring Python 3.6 or later to run (this could be reduced by using more long-winded equivalents to Python 3.6's ``f'...{x}'`` string interpolation syntax).\n\nIt is known to run on MacOS and Linux. It should run on Windows, but then, nothing is certain when Windows is involved, is it? Attempts to make it run on Windows are at your own risk.\n\n\n.. _MIDI Association: https://www.midi.org/specifications-old/category/smf-specifications\n.. _SMF Standard: MIDI Association_\n.. _MIDI Specification v1.0: https://www.midi.org/downloads?task=callelement&format=raw&item_id=92&element=f85c494b-2b32-4109-b8c1-083cca2b7db6&method=download\n.. _SMTPE Standard: https://ieeexplore.ieee.org/document/7291029\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "", "keywords": "MIDI", "license": "", "maintainer": "", "maintainer_email": "", "name": "MIDIFile", "package_url": "https://pypi.org/project/MIDIFile/", "platform": "", "project_url": "https://pypi.org/project/MIDIFile/", "project_urls": null, "release_url": "https://pypi.org/project/MIDIFile/0.1.0/", "requires_dist": null, "requires_python": ">=3.6, <4", "summary": "A simple MIDI File parser", "version": "0.1.0" }, "last_serial": 5914993, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "da42234fc1ce8e54e19d2d3db5a55fd4", "sha256": "cb32e87adff9a0ca07fbbe59d2ecf8cacb9c932c7510b019430a87c25f224b12" }, "downloads": -1, "filename": "MIDIFile-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "da42234fc1ce8e54e19d2d3db5a55fd4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6, <4", "size": 17684, "upload_time": "2019-10-01T21:24:38", "url": "https://files.pythonhosted.org/packages/69/18/17862a3823aff9918f8e4459c7a626e0185950d9827dfbbe9f9c13896016/MIDIFile-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1f8c007878dbcda54f59d63ed35abb81", "sha256": "8513a9e16cba0e37206136e31c52bd1ed58a6d65baa57b42aa94548deadaae98" }, "downloads": -1, "filename": "MIDIFile-0.1.0.tar.gz", "has_sig": false, "md5_digest": "1f8c007878dbcda54f59d63ed35abb81", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6, <4", "size": 22326, "upload_time": "2019-10-01T21:24:41", "url": "https://files.pythonhosted.org/packages/28/5a/7677899ce4d7a51fcd5598825d08c2a5b87a63859a91e58d1205c0077858/MIDIFile-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "da42234fc1ce8e54e19d2d3db5a55fd4", "sha256": "cb32e87adff9a0ca07fbbe59d2ecf8cacb9c932c7510b019430a87c25f224b12" }, "downloads": -1, "filename": "MIDIFile-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "da42234fc1ce8e54e19d2d3db5a55fd4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6, <4", "size": 17684, "upload_time": "2019-10-01T21:24:38", "url": "https://files.pythonhosted.org/packages/69/18/17862a3823aff9918f8e4459c7a626e0185950d9827dfbbe9f9c13896016/MIDIFile-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1f8c007878dbcda54f59d63ed35abb81", "sha256": "8513a9e16cba0e37206136e31c52bd1ed58a6d65baa57b42aa94548deadaae98" }, "downloads": -1, "filename": "MIDIFile-0.1.0.tar.gz", "has_sig": false, "md5_digest": "1f8c007878dbcda54f59d63ed35abb81", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6, <4", "size": 22326, "upload_time": "2019-10-01T21:24:41", "url": "https://files.pythonhosted.org/packages/28/5a/7677899ce4d7a51fcd5598825d08c2a5b87a63859a91e58d1205c0077858/MIDIFile-0.1.0.tar.gz" } ] }