├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── THANKS ├── doc └── wiki │ ├── core.1.png │ ├── drum_machine.jpg │ ├── improviser.jpg │ ├── keyboard.jpg │ ├── lpexample.png │ ├── mingusApplications.rst │ ├── mingusFeatures.rst │ ├── mingusIndex.rst │ ├── mingusSidebar.rst │ ├── refMingusContainersBar.rst │ ├── refMingusContainersComposition.rst │ ├── refMingusContainersGuitar.rst │ ├── refMingusContainersInstrument.rst │ ├── refMingusContainersMidiinstrument.rst │ ├── refMingusContainersMt_exceptions.rst │ ├── refMingusContainersNote.rst │ ├── refMingusContainersNote_container.rst │ ├── refMingusContainersNotecontainer.rst │ ├── refMingusContainersPiano.rst │ ├── refMingusContainersSuite.rst │ ├── refMingusContainersTrack.rst │ ├── refMingusCoreChords.rst │ ├── refMingusCoreIntervals.rst │ ├── refMingusCoreKeys.rst │ ├── refMingusCoreMeter.rst │ ├── refMingusCoreMt_exceptions.rst │ ├── refMingusCoreNotes.rst │ ├── refMingusCoreProgressions.rst │ ├── refMingusCoreScales.rst │ ├── refMingusCoreValue.rst │ ├── refMingusExtraFft.rst │ ├── refMingusExtraLilypond.rst │ ├── refMingusExtraMusicxml.rst │ ├── refMingusExtraStringtuning.rst │ ├── refMingusExtraTablature.rst │ ├── refMingusExtraTunings.rst │ ├── refMingusMidiFluidsynth.rst │ ├── refMingusMidiMidi_events.rst │ ├── refMingusMidiMidi_file_in.rst │ ├── refMingusMidiMidi_file_out.rst │ ├── refMingusMidiMidi_track.rst │ ├── refMingusMidiPyfluidsynth.rst │ ├── refMingusMidiSequencer.rst │ ├── refMingusMidiSequencer_observer.rst │ ├── refMingusMidiSequencerobserver.rst │ ├── tutorialBarModule.rst │ ├── tutorialChords.rst │ ├── tutorialCompositionModule.rst │ ├── tutorialCore.rst │ ├── tutorialDiatonic.rst │ ├── tutorialExtraLilypond.rst │ ├── tutorialFluidsynth.rst │ ├── tutorialGettingmingus.rst │ ├── tutorialInstrumentModule.rst │ ├── tutorialIntervals.rst │ ├── tutorialMeter.rst │ ├── tutorialMidiFileOut.rst │ ├── tutorialNote.rst │ ├── tutorialNoteContainerModule.rst │ ├── tutorialNoteModule.rst │ ├── tutorialProgressions.rst │ ├── tutorialScales.rst │ ├── tutorialSetup.rst │ ├── tutorialSuiteModule.rst │ └── tutorialTrackModule.rst ├── mingus ├── __init__.py ├── containers │ ├── __init__.py │ ├── bar.py │ ├── composition.py │ ├── instrument.py │ ├── mt_exceptions.py │ ├── note.py │ ├── note_container.py │ ├── suite.py │ └── track.py ├── core │ ├── __init__.py │ ├── chords.py │ ├── intervals.py │ ├── keys.py │ ├── meter.py │ ├── mt_exceptions.py │ ├── notes.py │ ├── progressions.py │ ├── scales.py │ └── value.py ├── extra │ ├── __init__.py │ ├── fft.py │ ├── lilypond.py │ ├── musicxml.py │ ├── tablature.py │ └── tunings.py └── midi │ ├── __init__.py │ ├── fluidsynth.py │ ├── midi_events.py │ ├── midi_file_in.py │ ├── midi_file_out.py │ ├── midi_track.py │ ├── pyfluidsynth.py │ ├── sequencer.py │ ├── sequencer_observer.py │ ├── win32midi.py │ └── win32midisequencer.py ├── mingus_examples ├── improviser │ └── improviser.py ├── play_progression │ └── play-progression.py ├── pygame-drum │ ├── pad.png │ └── pygame-drum.py └── pygame-piano │ ├── keys.png │ └── pygame-piano.py ├── requirements-dev.in ├── scripts ├── api_doc_generator.py ├── build_api_docs.sh └── build_github_pages.sh ├── setup.cfg ├── setup.py └── unittest ├── 440_880_clean.wav ├── 440_sine_clean.wav ├── example.sf2 ├── run_fluidsynth_tests.py ├── run_lilypond_tests.py ├── run_tests.py ├── test_bar.py ├── test_chords.py ├── test_composition.py ├── test_fft.py ├── test_fluidsynth.py ├── test_instrument.py ├── test_intervals.py ├── test_keys.py ├── test_lilypond.py ├── test_meter.py ├── test_musicxml.py ├── test_note.py ├── test_note_containers.py ├── test_notes.py ├── test_progressions.py ├── test_scales.py ├── test_suite.py ├── test_tablature.py ├── test_track.py ├── test_tunings.py └── test_value.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | MANIFEST 4 | build/ 5 | dist/ 6 | *.egg-info/ 7 | 8 | /venv 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.6.0] - 2020-01-04 2 | 3 | This is the first official release to support **Python 3** (≥ 3.5). I've tried not to break Python 2 compatibility, but I'm **officially not supporting Python 2.7** any further, especially since its end-of-life has come. 4 | 5 | Some other changes — both old, that had been merged but not released, and new — are also part of this release: 6 | 7 | ### Added 8 | * (#12) Add `channel` and `velocity` properties and setters to Note 9 | * (#18) Update LilyPond.from_Bar to handle minor, flat and sharp keys 10 | * Better documentation for developers and standardization of the development environment 11 | 12 | ### Changed 13 | * (#42) Fix: 3/x (3/8, 3/16, etc.) are not compound meters 14 | 15 | ### Fixed 16 | * (#11) Documentation fixes 17 | * (#14) Fix LilyPond filename extension detection 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributor Guide 2 | ================= 3 | 4 | Project Conventions 5 | ------------------- 6 | 7 | * **Source code formatting:** use [black][]. A recipe for running it is provided in the Makefile: just `make format`. 8 | 9 | 10 | Development setup 11 | ----------------- 12 | 13 | * Set up a Python virtual environment with `python -m venv venv` at the root of this project. 14 | * Run `make dev` to install the project in editable mode and install dependencies. 15 | 16 | ```shell 17 | $ python -m venv venv 18 | $ make dev 19 | ``` 20 | 21 | The Makefile is already configured to use Python from the virtual environment `venv`; for running other commands, activate it using `source venv/bin/activate`. 22 | 23 | 24 | [black]: https://black.readthedocs.io/en/stable/ 25 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include mingus *.py 2 | recursive-include mingus_examples *.py *.png 3 | recursive-include unittest *.py 4 | include LICENSE 5 | include THANKS 6 | include AUTHORS 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | project_dir := $(patsubst %/,%,$(dir $(realpath $(lastword $(MAKEFILE_LIST))))) 2 | PATH := $(project_dir)/venv/bin:$(PATH) 3 | 4 | all: 5 | 6 | format: 7 | python -m black mingus mingus_examples unittest 8 | 9 | dev: 10 | pip install -e '.[fft,fluidsynth]' -r requirements-dev.in 11 | 12 | install: 13 | pip install . 14 | 15 | test: 16 | (cd unittest; python run_tests.py) 17 | 18 | test-fluidsynth: 19 | (cd unittest; python run_fluidsynth_tests.py) 20 | 21 | test-lilypond: 22 | (cd unittest; python run_lilypond_tests.py) 23 | 24 | test-all: test test-fluidsynth test-lilypond 25 | 26 | clean: 27 | rm -rf build/ dist/ 28 | 29 | build: 30 | python setup.py sdist bdist_wheel 31 | 32 | sign-build: build 33 | (\ 34 | cd dist; \ 35 | rm -f *.asc; \ 36 | for a in *.whl *.gz; do \ 37 | gpg --armor --detach-sign "$$a"; \ 38 | done) 39 | 40 | upload: 41 | twine upload dist/* 42 | 43 | tag: 44 | git tag -s $$(python setup.py --version) 45 | 46 | release: clean build sign-build upload tag 47 | 48 | .PHONY: format \ 49 | dev install \ 50 | test test-fluidsynth test-lilypond test-all \ 51 | clean build \ 52 | upload tag release 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mingus 2 | ====== 3 | 4 | mingus is a package for Python used by programmers, musicians, composers 5 | and researchers to make and analyse music. 6 | 7 | Install with `pip install mingus` 8 | 9 | [Browse the documentation](http://bspaans.github.io/python-mingus/) 10 | 11 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | These people have contributed to mingus. Some have reported problems, others 2 | have contributed improvements to the documentation, actual code, and even 3 | complete modules. If your name has been left out, if you'd rather not be 4 | listed, or if you'd prefer a different address be used, please send a pull 5 | request. 6 | 7 | 8 | 9 | Albert Frantz albert.frantz@gmail.com 10 | Arun Chaganty arunchaganty@gmail.com 11 | Bart Spaans bart.spaans@gmail.com 12 | Ben Fisher jamon.ben@gmail.com 13 | Eduardo Dobay edudobay@gmail.com 14 | Gabriel gbsuar@gmail.com 15 | James Michael McDermott jamesmichaelmcdermott@gmail.com 16 | Javier Palance jpalanca@gmail.com 17 | Joshua Krohse jkrohse@gmail.com 18 | Nada Amin nada.amin@gmail.com 19 | Nathan Whitehead nwhitehe@gmail.com 20 | Stefan Huchler s.huchler@gmail.com 21 | -------------------------------------------------------------------------------- /doc/wiki/core.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/doc/wiki/core.1.png -------------------------------------------------------------------------------- /doc/wiki/drum_machine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/doc/wiki/drum_machine.jpg -------------------------------------------------------------------------------- /doc/wiki/improviser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/doc/wiki/improviser.jpg -------------------------------------------------------------------------------- /doc/wiki/keyboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/doc/wiki/keyboard.jpg -------------------------------------------------------------------------------- /doc/wiki/lpexample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/doc/wiki/lpexample.png -------------------------------------------------------------------------------- /doc/wiki/mingusApplications.rst: -------------------------------------------------------------------------------- 1 | Applications 2 | ============ 3 | 4 | This is an overview of some of the applications that use mingus. If you know of or have written another program, open a pull request or get in contact and we'll add it to the list. 5 | 6 | 7 | ---- 8 | 9 | 10 | Example Application: Drum Machine 11 | --------------------------------- 12 | 13 | *Description* A simple drum program with crude recording and playback support controlled by the keyboard. 14 | 15 | *Platform* All 16 | 17 | *Download* This program is included in mingus' `examples `_ directory. 18 | 19 | 20 | .. image:: drum_machine.jpg 21 | 22 | http://www.youtube.com/watch?v=FDdcz873tUQ 23 | 24 | 25 | 26 | 27 | ---- 28 | 29 | 30 | 31 | Example Application: Keyboard 32 | ----------------------------- 33 | 34 | *Description* A keyboard controlled keyboard (yeah). Determines chords while you play them. 35 | 36 | *Platform* All 37 | 38 | *Download* This program is included in mingus' `examples `_ directory. 39 | 40 | 41 | .. image:: keyboard.jpg 42 | 43 | http://www.youtube.com/watch?v=dKTMie3nY7M 44 | 45 | 46 | 47 | ---- 48 | 49 | 50 | Improviser 51 | ---------- 52 | 53 | *Description* Automatic music generation software. 54 | 55 | *Platform* All 56 | 57 | *Download* Available at http://pypi.python.org/pypi/improviser/ 58 | 59 | 60 | .. image:: improviser.jpg 61 | 62 | http://www.youtube.com/watch?v=K3lpZV-ZaWc 63 | 64 | 65 | 66 | 67 | ---- 68 | 69 | 70 | :doc:`Back to Index ` 71 | -------------------------------------------------------------------------------- /doc/wiki/mingusFeatures.rst: -------------------------------------------------------------------------------- 1 | Features 2 | ======== 3 | 4 | The mingus package is currently divided into four sub-packages named `core`, `containers`, `midi` and `extra`: 5 | 6 | =========== 7 | mingus.core 8 | =========== 9 | 10 | * Work with notes, intervals, chords, scales, keys and meters in a simple and theoretically sound way. 11 | * Generate natural diatonic intervals (seconds, thirds, fourths, etc) and absolute intervals (minors second, perfect fifths, etc.) 12 | * Generate natural diatonic triads, seventh chords, and absolute chords directly or from shorthand (min7, m/M7, etc). mingus also knows about inversions, slashed chords and polychords. 13 | * Refer to chords by their diatonic function (tonic, subtonic, etc. or I, ii, iii, IV, etc). 14 | * Generate chords from abstract chord progressions (eg. ["I", "IV", "V"]). Substitution algorithms are included. 15 | * Work with diatonic scales and their modes (ionian, mixolydian, etc.), generate the minor (natural, harmonic and melodic) and chromatic or whole note scales. 16 | * Recognize intervals, scales and hundreds of chords from lists of notes. 17 | * Recognize the harmonic functions of chords. 18 | 19 | ================= 20 | mingus.containers 21 | ================= 22 | 23 | * The Note class: can keep track of octaves, dynamics and effect and also allows you to compare Notes: eg. `Note("A") <= Note("B")` and convert to and from Hertz. 24 | * An Instrument class that can be subclassed. This can be used to work with the appropriate ranges, clefs, etc. 25 | * Data structures that group notes together in blocks of notes (NoteContainers), Bars, Tracks, Compositions and Suites. 26 | * Transpose functions on Notes, NoteContainers, Bars and Tracks. 27 | 28 | =========== 29 | mingus.midi 30 | =========== 31 | 32 | * Can convert all the objects in mingus.containers to MIDI events. 33 | * Can save MIDI events - and thus mingus.containers - as MIDI files. 34 | * A MIDI sequencer which uses the container objects and can send timed MIDI messages to an output function. 35 | * Support for fluidsynth (a software MIDI synthesizer), so that objects can be played in real-time. 36 | 37 | ============ 38 | mingus.extra 39 | ============ 40 | 41 | * Create png's and pdf's from Bars, Tracks, Compositions and Suites using LilyPond. 42 | 43 | 44 | ---- 45 | 46 | :doc:`Back to Index ` 47 | -------------------------------------------------------------------------------- /doc/wiki/mingusIndex.rst: -------------------------------------------------------------------------------- 1 | mingus 2 | ====== 3 | 4 | .. image:: doc/wiki/lpexample.png 5 | 6 | *mingus* is an advanced, cross-platform music theory and notation package for `Python `_ with MIDI file and playback support. It can be used to play around with music theory, to build editors, educational tools and other applications that need to process and/or play music. It can also be used to create sheet music with `LilyPond `_. 7 | 8 | =============== 9 | Getting Started 10 | =============== 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | :name: mastertoc 15 | 16 | doc/wiki/mingusFeatures 17 | doc/wiki/tutorialGettingmingus 18 | doc/wiki/tutorialSetup 19 | doc/wiki/mingusApplications 20 | 21 | 22 | 23 | ========= 24 | Tutorials 25 | ========= 26 | 27 | 28 | 29 | .. toctree:: 30 | :maxdepth: 1 31 | :caption: Fundamentals: Exploring `mingus.core` 32 | :name: minguscore 33 | 34 | doc/wiki/tutorialNote 35 | doc/wiki/tutorialDiatonic 36 | doc/wiki/tutorialIntervals 37 | doc/wiki/tutorialChords 38 | doc/wiki/tutorialScales 39 | doc/wiki/tutorialMeter 40 | doc/wiki/tutorialProgressions 41 | doc/wiki/tutorialCore 42 | 43 | 44 | .. toctree:: 45 | :maxdepth: 1 46 | :caption: Grouping Notes: Exploring `mingus.containers` 47 | 48 | doc/wiki/tutorialNoteModule 49 | doc/wiki/tutorialNoteContainerModule 50 | doc/wiki/tutorialBarModule 51 | doc/wiki/tutorialInstrumentModule 52 | doc/wiki/tutorialTrackModule 53 | doc/wiki/tutorialCompositionModule 54 | doc/wiki/tutorialSuiteModule 55 | 56 | 57 | 58 | .. toctree:: 59 | :maxdepth: 1 60 | :caption: Midi: Exploring `mingus.midi` 61 | 62 | doc/wiki/tutorialFluidsynth 63 | doc/wiki/tutorialMidiFileOut 64 | 65 | 66 | 67 | .. toctree:: 68 | :maxdepth: 1 69 | :caption: Extras: Exploring `mingus.extra` 70 | 71 | doc/wiki/tutorialExtraLilypond 72 | 73 | 74 | ---- 75 | 76 | 77 | ======== 78 | API docs 79 | ======== 80 | 81 | .. toctree:: 82 | :maxdepth: 1 83 | :caption: mingus.core 84 | 85 | doc/wiki/refMingusCoreNotes 86 | doc/wiki/refMingusCoreDiatonic 87 | doc/wiki/refMingusCoreIntervals 88 | doc/wiki/refMingusCoreChords 89 | doc/wiki/refMingusCoreScales 90 | doc/wiki/refMingusCoreKeys 91 | doc/wiki/refMingusCoreMeter 92 | doc/wiki/refMingusCoreValue 93 | doc/wiki/refMingusCoreProgressions 94 | 95 | .. toctree:: 96 | :maxdepth: 1 97 | :caption: mingus.containers 98 | 99 | doc/wiki/refMingusContainersNote 100 | doc/wiki/refMingusContainersNote_container 101 | doc/wiki/refMingusContainersBar 102 | doc/wiki/refMingusContainersInstrument 103 | doc/wiki/refMingusContainersTrack 104 | doc/wiki/refMingusContainersComposition 105 | doc/wiki/refMingusContainersSuite 106 | 107 | .. toctree:: 108 | :maxdepth: 1 109 | :caption: mingus.midi 110 | 111 | doc/wiki/refMingusMidiSequencer 112 | doc/wiki/refMingusMidiSequencerobserver 113 | doc/wiki/refMingusMidiMidi_events 114 | doc/wiki/refMingusMidiFluidsynth 115 | doc/wiki/refMingusMidiPyfluidsynth 116 | doc/wiki/refMingusMidiMidi_track 117 | doc/wiki/refMingusMidiMidi_file_out 118 | doc/wiki/refMingusMidiMidi_file_in 119 | 120 | .. toctree:: 121 | :maxdepth: 1 122 | :caption: mingus.extra 123 | 124 | doc/wiki/refMingusExtraLilypond 125 | doc/wiki/refMingusExtraTunings 126 | doc/wiki/refMingusExtraStringtuning 127 | doc/wiki/refMingusExtraTablature 128 | doc/wiki/refMingusExtraFft 129 | 130 | -------------------------------------------------------------------------------- /doc/wiki/mingusSidebar.rst: -------------------------------------------------------------------------------- 1 | * [mingusIndex Index] 2 | * [mingusFeatures Features] 3 | * [tutorialGettingmingus Getting mingus] 4 | * [tutorialSetup Setup] 5 | * [mingusApplications Applications Using mingus] 6 | * [mingusContact Contact] 7 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersBar.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.bar 2 | 3 | ===================== 4 | mingus.containers.bar 5 | ===================== 6 | 7 | 8 | .. class:: Bar 9 | 10 | 11 | .. method:: __add__(self, note_container) 12 | 13 | Enable the '+' operator on Bars. 14 | 15 | 16 | .. method:: __eq__(self, other) 17 | 18 | Enable the '==' operator for Bars. 19 | 20 | 21 | .. method:: __getitem__(self, index) 22 | 23 | Enable the '[]' notation on Bars to get the item at the index. 24 | 25 | 26 | .. method:: __init__(self, key=C, meter=(4, 4)) 27 | 28 | 29 | .. method:: __len__(self) 30 | 31 | Enable the len() method for Bars. 32 | 33 | 34 | .. method:: __repr__(self) 35 | 36 | Enable str() and repr() for Bars. 37 | 38 | 39 | .. method:: __setitem__(self, index, value) 40 | 41 | Enable the use of [] = notation on Bars. 42 | 43 | The value should be a NoteContainer, or a string/list/Note 44 | understood by the NoteContainer. 45 | 46 | 47 | .. method:: augment(self) 48 | 49 | Augment the NoteContainers in Bar. 50 | 51 | 52 | .. attribute:: bar 53 | 54 | Attribute of type: list 55 | ``[]`` 56 | 57 | .. method:: change_note_duration(self, at, to) 58 | 59 | Change the note duration at the given index to the given 60 | duration. 61 | 62 | 63 | .. attribute:: current_beat 64 | 65 | Attribute of type: float 66 | ``0.0`` 67 | 68 | .. method:: determine_chords(self, shorthand=False) 69 | 70 | Return a list of lists [place_in_beat, possible_chords]. 71 | 72 | 73 | .. method:: determine_progression(self, shorthand=False) 74 | 75 | Return a list of lists [place_in_beat, possible_progressions]. 76 | 77 | 78 | .. method:: diminish(self) 79 | 80 | Diminish the NoteContainers in Bar. 81 | 82 | 83 | .. method:: empty(self) 84 | 85 | Empty the Bar, remove all the NoteContainers. 86 | 87 | 88 | .. method:: get_note_names(self) 89 | 90 | Return a list of unique note names in the Bar. 91 | 92 | 93 | .. method:: get_range(self) 94 | 95 | Return the highest and the lowest note in a tuple. 96 | 97 | 98 | .. method:: is_full(self) 99 | 100 | Return False if there is room in this Bar for another 101 | NoteContainer, True otherwise. 102 | 103 | 104 | .. attribute:: key 105 | 106 | Attribute of type: str 107 | ``'C'`` 108 | 109 | .. attribute:: length 110 | 111 | Attribute of type: float 112 | ``0.0`` 113 | 114 | .. attribute:: meter 115 | 116 | Attribute of type: tuple 117 | ``(4, 4)`` 118 | 119 | .. method:: place_notes(self, notes, duration) 120 | 121 | Place the notes on the current_beat. 122 | 123 | Notes can be strings, Notes, list of strings, list of Notes or a 124 | NoteContainer. 125 | 126 | Raise a MeterFormatError if the duration is not valid. 127 | 128 | Return True if succesful, False otherwise (ie. the Bar hasn't got 129 | enough room for a note of that duration). 130 | 131 | 132 | .. method:: place_notes_at(self, notes, at) 133 | 134 | Place notes at the given index. 135 | 136 | 137 | .. method:: place_rest(self, duration) 138 | 139 | Place a rest of given duration on the current_beat. 140 | 141 | The same as place_notes(None, duration). 142 | 143 | 144 | .. method:: remove_last_entry(self) 145 | 146 | Remove the last NoteContainer in the Bar. 147 | 148 | 149 | .. method:: set_meter(self, meter) 150 | 151 | Set the meter of this bar. 152 | 153 | Meters in mingus are represented by a single tuple. 154 | 155 | If the format of the meter is not recognised, a MeterFormatError 156 | will be raised. 157 | 158 | 159 | .. method:: space_left(self) 160 | 161 | Return the space left on the Bar. 162 | 163 | 164 | .. method:: transpose(self, interval, up=True) 165 | 166 | Transpose the notes in the bar up or down the interval. 167 | 168 | Call transpose() on all NoteContainers in the bar. 169 | 170 | 171 | .. method:: value_left(self) 172 | 173 | Return the value left on the Bar. 174 | 175 | ---- 176 | 177 | 178 | 179 | :doc:`Back to Index` 180 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersComposition.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.composition 2 | 3 | ============================= 4 | mingus.containers.composition 5 | ============================= 6 | 7 | 8 | .. class:: Composition 9 | 10 | 11 | .. method:: __add__(self, value) 12 | 13 | Enable the '+' operator for Compositions. 14 | 15 | Notes, note strings, NoteContainers, Bars and Tracks are accepted. 16 | 17 | 18 | .. method:: __getitem__(self, index) 19 | 20 | Enable the '[]' notation. 21 | 22 | 23 | .. method:: __init__(self) 24 | 25 | 26 | .. method:: __len__(self) 27 | 28 | Enable the len() function. 29 | 30 | 31 | .. method:: __repr__(self) 32 | 33 | Return a string representing the class. 34 | 35 | 36 | .. method:: __setitem__(self, index, value) 37 | 38 | Enable the '[] =' notation. 39 | 40 | 41 | .. method:: add_note(self, note) 42 | 43 | Add a note to the selected tracks. 44 | 45 | Everything container.Track supports in __add__ is accepted. 46 | 47 | 48 | .. method:: add_track(self, track) 49 | 50 | Add a track to the composition. 51 | 52 | Raise an UnexpectedObjectError if the argument is not a 53 | mingus.containers.Track object. 54 | 55 | 56 | .. attribute:: author 57 | 58 | Attribute of type: str 59 | ``''`` 60 | 61 | .. attribute:: description 62 | 63 | Attribute of type: str 64 | ``''`` 65 | 66 | .. attribute:: email 67 | 68 | Attribute of type: str 69 | ``''`` 70 | 71 | .. method:: empty(self) 72 | 73 | Remove all the tracks from this class. 74 | 75 | 76 | .. method:: reset(self) 77 | 78 | Reset the information in this class. 79 | 80 | Remove the track and composer information. 81 | 82 | 83 | .. attribute:: selected_tracks 84 | 85 | Attribute of type: list 86 | ``[]`` 87 | 88 | .. method:: set_author(self, author=, email=) 89 | 90 | Set the title and author of the piece. 91 | 92 | 93 | .. method:: set_title(self, title=Untitled, subtitle=) 94 | 95 | Set the title and subtitle of the piece. 96 | 97 | 98 | .. attribute:: subtitle 99 | 100 | Attribute of type: str 101 | ``''`` 102 | 103 | .. attribute:: title 104 | 105 | Attribute of type: str 106 | ``'Untitled'`` 107 | 108 | .. attribute:: tracks 109 | 110 | Attribute of type: list 111 | ``[]`` 112 | ---- 113 | 114 | 115 | 116 | :doc:`Back to Index` 117 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersGuitar.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.Guitar 2 | 3 | ======================== 4 | mingus.containers.Guitar 5 | ======================== 6 | 7 | 8 | ---- 9 | 10 | .. data:: clef 11 | 12 | Attribute of type: str 13 | ``'Treble'`` 14 | 15 | ---- 16 | 17 | .. data:: name 18 | 19 | Attribute of type: str 20 | ``'Guitar'`` 21 | 22 | ---- 23 | 24 | .. data:: range 25 | 26 | Attribute of type: tuple 27 | ``('E-3', 'E-7')`` 28 | 29 | ---- 30 | 31 | .. data:: tuning 32 | 33 | Attribute of type: NoneType 34 | ``None`` 35 | 36 | ---- 37 | 38 | .. function:: __init__(self) 39 | 40 | 41 | ---- 42 | 43 | .. function:: __repr__(self) 44 | 45 | Return a string representing the object. 46 | 47 | 48 | ---- 49 | 50 | .. function:: can_play_notes(self, notes) 51 | 52 | 53 | ---- 54 | 55 | .. function:: note_in_range(self, note) 56 | 57 | Test whether note is in the range of this Instrument. 58 | 59 | Return True if so, False otherwise. 60 | 61 | 62 | ---- 63 | 64 | .. function:: notes_in_range(self, notes) 65 | 66 | An alias for can_play_notes. 67 | 68 | 69 | ---- 70 | 71 | .. function:: set_range(self, range) 72 | 73 | Set the range of the instrument. 74 | 75 | A range is a tuple of two Notes or note strings. 76 | 77 | ---- 78 | 79 | 80 | 81 | :doc:`Back to Index` 82 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersMidiinstrument.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.MidiInstrument 2 | 3 | ================================ 4 | mingus.containers.MidiInstrument 5 | ================================ 6 | 7 | 8 | ---- 9 | 10 | .. data:: clef 11 | 12 | Attribute of type: str 13 | ``'bass and treble'`` 14 | 15 | ---- 16 | 17 | .. data:: instrument_nr 18 | 19 | Attribute of type: int 20 | ``1`` 21 | 22 | ---- 23 | 24 | .. data:: name 25 | 26 | Attribute of type: str 27 | ``''`` 28 | 29 | ---- 30 | 31 | .. data:: names 32 | 33 | Attribute of type: list 34 | ``['Acoustic Grand Piano', 'Bright Acoustic Piano', 'Electric Grand Piano', 'Honky-tonk Piano', 'Electric Piano 1', 'Electric Piano 2', 'Harpsichord', 'Clavi', 'Celesta', 'Glockenspiel', 'Music Box', 'Vibraphone', 'Marimba', 'Xylophone', 'Tubular Bells', 'Dulcimer', 'Drawbar Organ', 'Percussive Organ', 'Rock Organ', 'Church Organ', 'Reed Organ', 'Accordion', 'Harmonica', 'Tango Accordion', 'Acoustic Guitar (nylon)', 'Acoustic Guitar (steel)', 'Electric Guitar (jazz)', 'Electric Guitar (clean)', 'Electric Guitar (muted)', 'Overdriven Guitar', 'Distortion Guitar', 'Guitar harmonics', 'Acoustic Bass', 'Electric Bass (finger)', 'Electric Bass (pick)', 'Fretless Bass', 'Slap Bass 1', 'Slap Bass 2', 'Synth Bass 1', 'Synth Bass 2', 'Violin', 'Viola', 'Cello', 'Contrabass', 'Tremolo Strings', 'Pizzicato Strings', 'Orchestral Harp', 'Timpani', 'String Ensemble 1', 'String Ensemble 2', 'SynthStrings 1', 'SynthStrings 2', 'Choir Aahs', 'Voice Oohs', 'Synth Voice', 'Orchestra Hit', 'Trumpet', 'Trombone', 'Tuba', 'Muted Trumpet', 'French Horn', 'Brass Section', 'SynthBrass 1', 'SynthBrass 2', 'Soprano Sax', 'Alto Sax', 'Tenor Sax', 'Baritone Sax', 'Oboe', 'English Horn', 'Bassoon', 'Clarinet', 'Piccolo', 'Flute', 'Recorder', 'Pan Flute', 'Blown Bottle', 'Shakuhachi', 'Whistle', 'Ocarina', 'Lead1 (square)', 'Lead2 (sawtooth)', 'Lead3 (calliope)', 'Lead4 (chiff)', 'Lead5 (charang)', 'Lead6 (voice)', 'Lead7 (fifths)', 'Lead8 (bass + lead)', 'Pad1 (new age)', 'Pad2 (warm)', 'Pad3 (polysynth)', 'Pad4 (choir)', 'Pad5 (bowed)', 'Pad6 (metallic)', 'Pad7 (halo)', 'Pad8 (sweep)', 'FX1 (rain)', 'FX2 (soundtrack)', 'FX 3 (crystal)', 'FX 4 (atmosphere)', 'FX 5 (brightness)', 'FX 6 (goblins)', 'FX 7 (echoes)', 'FX 8 (sci-fi)', 'Sitar', 'Banjo', 'Shamisen', 'Koto', 'Kalimba', 'Bag pipe', 'Fiddle', 'Shanai', 'Tinkle Bell', 'Agogo', 'Steel Drums', 'Woodblock', 'Taiko Drum', 'Melodic Tom', 'Synth Drum', 'Reverse Cymbal', 'Guitar Fret Noise', 'Breath Noise', 'Seashore', 'Bird Tweet', 'Telephone Ring', 'Helicopter', 'Applause', 'Gunshot']`` 35 | 36 | ---- 37 | 38 | .. data:: range 39 | 40 | Attribute of type: tuple 41 | ``('C-0', 'B-8')`` 42 | 43 | ---- 44 | 45 | .. data:: tuning 46 | 47 | Attribute of type: NoneType 48 | ``None`` 49 | 50 | ---- 51 | 52 | .. function:: __init__(self, name=) 53 | 54 | 55 | ---- 56 | 57 | .. function:: __repr__(self) 58 | 59 | Return a string representing the object. 60 | 61 | 62 | ---- 63 | 64 | .. function:: can_play_notes(self, notes) 65 | 66 | Test if the notes lie within the range of the instrument. 67 | 68 | Return True if so, False otherwise. 69 | 70 | 71 | ---- 72 | 73 | .. function:: note_in_range(self, note) 74 | 75 | Test whether note is in the range of this Instrument. 76 | 77 | Return True if so, False otherwise. 78 | 79 | 80 | ---- 81 | 82 | .. function:: notes_in_range(self, notes) 83 | 84 | An alias for can_play_notes. 85 | 86 | 87 | ---- 88 | 89 | .. function:: set_range(self, range) 90 | 91 | Set the range of the instrument. 92 | 93 | A range is a tuple of two Notes or note strings. 94 | 95 | ---- 96 | 97 | 98 | 99 | :doc:`Back to Index` 100 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersMt_exceptions.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.mt_exceptions 2 | 3 | =============================== 4 | mingus.containers.mt_exceptions 5 | =============================== 6 | 7 | 8 | .. class:: InstrumentRangeError 9 | 10 | 11 | .. attribute:: args 12 | 13 | Attribute of type: getset_descriptor 14 | ```` 15 | 16 | .. attribute:: message 17 | 18 | Attribute of type: getset_descriptor 19 | ```` 20 | 21 | .. class:: MeterFormatError 22 | 23 | 24 | .. attribute:: args 25 | 26 | Attribute of type: getset_descriptor 27 | ```` 28 | 29 | .. attribute:: message 30 | 31 | Attribute of type: getset_descriptor 32 | ```` 33 | 34 | .. class:: NoteFormatError 35 | 36 | 37 | .. attribute:: args 38 | 39 | Attribute of type: getset_descriptor 40 | ```` 41 | 42 | .. attribute:: message 43 | 44 | Attribute of type: getset_descriptor 45 | ```` 46 | 47 | .. class:: UnexpectedObjectError 48 | 49 | 50 | .. attribute:: args 51 | 52 | Attribute of type: getset_descriptor 53 | ```` 54 | 55 | .. attribute:: message 56 | 57 | Attribute of type: getset_descriptor 58 | ```` 59 | ---- 60 | 61 | 62 | 63 | :doc:`Back to Index` 64 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersNote.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.note 2 | 3 | ====================== 4 | mingus.containers.note 5 | ====================== 6 | 7 | 8 | .. class:: Note 9 | 10 | 11 | .. method:: __eq__(self, other) 12 | 13 | Compare Notes for equality by comparing their note values. 14 | 15 | 16 | .. method:: __ge__(self, other) 17 | 18 | 19 | .. method:: __gt__(self, other) 20 | 21 | 22 | .. method:: __init__(self, name=C, octave=4, dynamics={}) 23 | 24 | 25 | .. method:: __int__(self) 26 | 27 | Return the current octave multiplied by twelve and add 28 | notes.note_to_int to it. 29 | 30 | This means a C-0 returns 0, C-1 returns 12, etc. This method allows 31 | you to use int() on Notes. 32 | 33 | 34 | .. method:: __le__(self, other) 35 | 36 | 37 | .. method:: __lt__(self, other) 38 | 39 | Enable the comparing operators on Notes (>, <, \ ==, !=, >= and <=). 40 | 41 | So we can sort() Intervals, etc. 42 | 43 | Examples: 44 | 45 | >>> Note('C', 4) < Note('B', 4) 46 | True 47 | >>> Note('C', 4) > Note('B', 4) 48 | False 49 | 50 | 51 | .. method:: __ne__(self, other) 52 | 53 | 54 | .. method:: __repr__(self) 55 | 56 | Return a helpful representation for printing Note classes. 57 | 58 | 59 | .. method:: augment(self) 60 | 61 | Call notes.augment with this note as argument. 62 | 63 | 64 | .. method:: change_octave(self, diff) 65 | 66 | Change the octave of the note to the current octave + diff. 67 | 68 | 69 | .. method:: diminish(self) 70 | 71 | Call notes.diminish with this note as argument. 72 | 73 | 74 | .. attribute:: dynamics 75 | 76 | Attribute of type: dict 77 | ``{}`` 78 | 79 | .. method:: empty(self) 80 | 81 | Remove the data in the instance. 82 | 83 | 84 | .. method:: from_hertz(self, hertz, standard_pitch=440) 85 | 86 | Set the Note name and pitch, calculated from the hertz value. 87 | 88 | The standard_pitch argument can be used to set the pitch of A-4, 89 | from which the rest is calculated. 90 | 91 | 92 | .. method:: from_int(self, integer) 93 | 94 | Set the Note corresponding to the integer. 95 | 96 | 0 is a C on octave 0, 12 is a C on octave 1, etc. 97 | 98 | Example: 99 | 100 | >>> Note().from_int(12) 101 | 'C-1' 102 | 103 | 104 | .. method:: from_shorthand(self, shorthand) 105 | 106 | Convert from traditional Helmhotz pitch notation. 107 | 108 | Examples: 109 | 110 | >>> Note().from_shorthand("C,,") 111 | 'C-0' 112 | >>> Note().from_shorthand("C") 113 | 'C-2' 114 | >>> Note().from_shorthand("c'") 115 | 'C-4' 116 | 117 | 118 | .. method:: measure(self, other) 119 | 120 | Return the number of semitones between this Note and the other. 121 | 122 | Examples: 123 | 124 | >>> Note('C').measure(Note('D')) 125 | 2 126 | >>> Note('D').measure(Note('C')) 127 | -2 128 | 129 | 130 | .. attribute:: name 131 | 132 | Attribute of type: str 133 | ``'C'`` 134 | 135 | .. attribute:: octave 136 | 137 | Attribute of type: int 138 | ``4`` 139 | 140 | .. method:: octave_down(self) 141 | 142 | Decrement the current octave with 1. 143 | 144 | 145 | .. method:: octave_up(self) 146 | 147 | Increment the current octave with 1. 148 | 149 | 150 | .. method:: remove_redundant_accidentals(self) 151 | 152 | Call notes.remove_redundant_accidentals on this note's name. 153 | 154 | 155 | .. method:: set_note(self, name=C, octave=4, dynamics={}) 156 | 157 | Set the note to name in octave with dynamics. 158 | 159 | Return the objects if it succeeded, raise an NoteFormatError 160 | otherwise. 161 | 162 | 163 | .. method:: to_hertz(self, standard_pitch=440) 164 | 165 | Return the Note in Hz. 166 | 167 | The standard_pitch argument can be used to set the pitch of A-4, 168 | from which the rest is calculated. 169 | 170 | 171 | .. method:: to_shorthand(self) 172 | 173 | Give the traditional Helmhotz pitch notation. 174 | 175 | Examples: 176 | 177 | >>> Note('C-4').to_shorthand() 178 | "c'" 179 | >>> Note('C-3').to_shorthand() 180 | 'c' 181 | >>> Note('C-2').to_shorthand() 182 | 'C' 183 | >>> Note('C-1').to_shorthand() 184 | 'C,' 185 | 186 | 187 | .. method:: transpose(self, interval, up=True) 188 | 189 | Transpose the note up or down the interval. 190 | 191 | Examples: 192 | 193 | >>> a = Note('A') 194 | >>> a.transpose('3') 195 | >>> a 196 | 'C#-5' 197 | >>> a.transpose('3', False) 198 | >>> a 199 | 'A-4' 200 | 201 | ---- 202 | 203 | 204 | 205 | :doc:`Back to Index` 206 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersPiano.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.Piano 2 | 3 | ======================= 4 | mingus.containers.Piano 5 | ======================= 6 | 7 | 8 | ---- 9 | 10 | .. data:: clef 11 | 12 | Attribute of type: str 13 | ``'bass and treble'`` 14 | 15 | ---- 16 | 17 | .. data:: name 18 | 19 | Attribute of type: str 20 | ``'Piano'`` 21 | 22 | ---- 23 | 24 | .. data:: range 25 | 26 | Attribute of type: tuple 27 | ``('F-0', 'B-8')`` 28 | 29 | ---- 30 | 31 | .. data:: tuning 32 | 33 | Attribute of type: NoneType 34 | ``None`` 35 | 36 | ---- 37 | 38 | .. function:: __init__(self) 39 | 40 | 41 | ---- 42 | 43 | .. function:: __repr__(self) 44 | 45 | Return a string representing the object. 46 | 47 | 48 | ---- 49 | 50 | .. function:: can_play_notes(self, notes) 51 | 52 | Test if the notes lie within the range of the instrument. 53 | 54 | Return True if so, False otherwise. 55 | 56 | 57 | ---- 58 | 59 | .. function:: note_in_range(self, note) 60 | 61 | Test whether note is in the range of this Instrument. 62 | 63 | Return True if so, False otherwise. 64 | 65 | 66 | ---- 67 | 68 | .. function:: notes_in_range(self, notes) 69 | 70 | An alias for can_play_notes. 71 | 72 | 73 | ---- 74 | 75 | .. function:: set_range(self, range) 76 | 77 | Set the range of the instrument. 78 | 79 | A range is a tuple of two Notes or note strings. 80 | 81 | ---- 82 | 83 | 84 | 85 | :doc:`Back to Index` 86 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersSuite.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.suite 2 | 3 | ======================= 4 | mingus.containers.suite 5 | ======================= 6 | 7 | 8 | .. class:: Suite 9 | 10 | 11 | .. method:: __add__(self, composition) 12 | 13 | Enable the '+' operator for Compositions. 14 | 15 | 16 | .. method:: __getitem__(self, index) 17 | 18 | Enable the '[]' notation. 19 | 20 | 21 | .. method:: __init__(self) 22 | 23 | 24 | .. method:: __len__(self) 25 | 26 | Enable the len() function. 27 | 28 | 29 | .. method:: __setitem__(self, index, value) 30 | 31 | Enable the '[] =' notation. 32 | 33 | 34 | .. method:: add_composition(self, composition) 35 | 36 | Add a composition to the suite. 37 | 38 | Raise an UnexpectedObjectError when the supplied argument is not a 39 | Composition object. 40 | 41 | 42 | .. attribute:: author 43 | 44 | Attribute of type: str 45 | ``''`` 46 | 47 | .. attribute:: compositions 48 | 49 | Attribute of type: list 50 | ``[]`` 51 | 52 | .. attribute:: description 53 | 54 | Attribute of type: str 55 | ``''`` 56 | 57 | .. attribute:: email 58 | 59 | Attribute of type: str 60 | ``''`` 61 | 62 | .. method:: set_author(self, author, email=) 63 | 64 | Set the author of the suite. 65 | 66 | 67 | .. method:: set_title(self, title, subtitle=) 68 | 69 | Set the title and the subtitle of the suite. 70 | 71 | 72 | .. attribute:: subtitle 73 | 74 | Attribute of type: str 75 | ``''`` 76 | 77 | .. attribute:: title 78 | 79 | Attribute of type: str 80 | ``'Untitled'`` 81 | ---- 82 | 83 | 84 | 85 | :doc:`Back to Index` 86 | -------------------------------------------------------------------------------- /doc/wiki/refMingusContainersTrack.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.containers.track 2 | 3 | ======================= 4 | mingus.containers.track 5 | ======================= 6 | 7 | 8 | .. class:: Track 9 | 10 | 11 | .. method:: __add__(self, value) 12 | 13 | Enable the '+' operator for Tracks. 14 | 15 | Notes, notes as string, NoteContainers and Bars accepted. 16 | 17 | 18 | .. method:: __eq__(self, other) 19 | 20 | Enable the '==' operator for tracks. 21 | 22 | 23 | .. method:: __getitem__(self, index) 24 | 25 | Enable the '[]' notation for Tracks. 26 | 27 | 28 | .. method:: __init__(self, instrument=None) 29 | 30 | 31 | .. method:: __len__(self) 32 | 33 | Enable the len() function for Tracks. 34 | 35 | 36 | .. method:: __repr__(self) 37 | 38 | Return a string representing the class. 39 | 40 | 41 | .. method:: __setitem__(self, index, value) 42 | 43 | Enable the '[] =' notation for Tracks. 44 | 45 | Throw an UnexpectedObjectError if the value being set is not a 46 | mingus.containers.Bar object. 47 | 48 | 49 | .. method:: add_bar(self, bar) 50 | 51 | Add a Bar to the current track. 52 | 53 | 54 | .. method:: add_notes(self, note, duration=None) 55 | 56 | Add a Note, note as string or NoteContainer to the last Bar. 57 | 58 | If the Bar is full, a new one will automatically be created. 59 | 60 | If the Bar is not full but the note can't fit in, this method will 61 | return False. True otherwise. 62 | 63 | An InstrumentRangeError exception will be raised if an Instrument is 64 | attached to the Track, but the note turns out not to be within the 65 | range of the Instrument. 66 | 67 | 68 | .. method:: augment(self) 69 | 70 | Augment all the bars in the Track. 71 | 72 | 73 | .. attribute:: bars 74 | 75 | Attribute of type: list 76 | ``[]`` 77 | 78 | .. method:: diminish(self) 79 | 80 | Diminish all the bars in the Track. 81 | 82 | 83 | .. method:: from_chords(self, chords, duration=1) 84 | 85 | Add chords to the Track. 86 | 87 | The given chords should be a list of shorthand strings or list of 88 | list of shorthand strings, etc. 89 | 90 | Each sublist divides the value by 2. 91 | 92 | If a tuning is set, chords will be expanded so they have a proper 93 | fingering. 94 | 95 | Example: 96 | 97 | >>> t = Track().from_chords(['C', ['Am', 'Dm'], 'G7', 'C#'], 1) 98 | 99 | 100 | .. method:: get_notes(self) 101 | 102 | Return an iterator that iterates through every bar in the this 103 | track. 104 | 105 | 106 | .. method:: get_tuning(self) 107 | 108 | Return a StringTuning object. 109 | 110 | If an instrument is set and has a tuning it will be returned. 111 | Otherwise the track's one will be used. 112 | 113 | 114 | .. attribute:: instrument 115 | 116 | Attribute of type: NoneType 117 | ``None`` 118 | 119 | .. attribute:: name 120 | 121 | Attribute of type: str 122 | ``'Untitled'`` 123 | 124 | .. method:: set_tuning(self, tuning) 125 | 126 | Set the tuning attribute on both the Track and its instrument (when 127 | available). 128 | 129 | Tuning should be a StringTuning or derivative object. 130 | 131 | 132 | .. method:: test_integrity(self) 133 | 134 | Test whether all but the last Bars contained in this track are 135 | full. 136 | 137 | 138 | .. method:: transpose(self, interval, up=True) 139 | 140 | Transpose all the notes in the track up or down the interval. 141 | 142 | Call transpose() on every Bar. 143 | 144 | 145 | .. attribute:: tuning 146 | 147 | Attribute of type: NoneType 148 | ``None`` 149 | ---- 150 | 151 | 152 | 153 | :doc:`Back to Index` 154 | -------------------------------------------------------------------------------- /doc/wiki/refMingusCoreKeys.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.core.keys 2 | 3 | ================ 4 | mingus.core.keys 5 | ================ 6 | 7 | Module for dealing with keys. 8 | 9 | This module provides a simple interface for dealing with keys. 10 | 11 | 12 | 13 | .. class:: Key 14 | 15 | 16 | .. method:: __eq__(self, other) 17 | 18 | 19 | .. method:: __init__(self, key=C) 20 | 21 | 22 | .. method:: __ne__(self, other) 23 | 24 | 25 | ---- 26 | 27 | .. data:: base_scale 28 | 29 | Attribute of type: list 30 | ``['C', 'D', 'E', 'F', 'G', 'A', 'B']`` 31 | 32 | ---- 33 | 34 | .. data:: couple 35 | 36 | Attribute of type: tuple 37 | ``('C#', 'a#')`` 38 | 39 | ---- 40 | 41 | .. data:: keys 42 | 43 | Attribute of type: list 44 | ``[('Cb', 'ab'), ('Gb', 'eb'), ('Db', 'bb'), ('Ab', 'f'), ('Eb', 'c'), ('Bb', 'g'), ('F', 'd'), ('C', 'a'), ('G', 'e'), ('D', 'b'), ('A', 'f#'), ('E', 'c#'), ('B', 'g#'), ('F#', 'd#'), ('C#', 'a#')]`` 45 | 46 | ---- 47 | 48 | .. data:: major_keys 49 | 50 | Attribute of type: list 51 | ``['Cb', 'Gb', 'Db', 'Ab', 'Eb', 'Bb', 'F', 'C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#']`` 52 | 53 | ---- 54 | 55 | .. data:: minor_keys 56 | 57 | Attribute of type: list 58 | ``['ab', 'eb', 'bb', 'f', 'c', 'g', 'd', 'a', 'e', 'b', 'f#', 'c#', 'g#', 'd#', 'a#']`` 59 | 60 | ---- 61 | 62 | .. function:: get_key(accidentals=0) 63 | 64 | Return the key corrisponding to accidentals. 65 | 66 | Return the tuple containing the major key corrensponding to the 67 | accidentals put as input, and his relative minor; negative numbers for 68 | flats, positive numbers for sharps. 69 | 70 | 71 | ---- 72 | 73 | .. function:: get_key_signature(key=C) 74 | 75 | Return the key signature. 76 | 77 | 0 for C or a, negative numbers for flat key signatures, positive numbers 78 | for sharp key signatures. 79 | 80 | 81 | ---- 82 | 83 | .. function:: get_key_signature_accidentals(key=C) 84 | 85 | Return the list of accidentals present into the key signature. 86 | 87 | 88 | ---- 89 | 90 | .. function:: get_notes(key=C) 91 | 92 | Return an ordered list of the notes in this natural key. 93 | 94 | Examples: 95 | 96 | >>> get_notes('F') 97 | ['F', 'G', 'A', 'Bb', 'C', 'D', 'E'] 98 | >>> get_notes('c') 99 | ['C', 'D', 'Eb', 'F', 'G', 'Ab', 'Bb'] 100 | 101 | 102 | ---- 103 | 104 | .. function:: is_valid_key(key) 105 | 106 | Return True if key is in a recognized format. False if not. 107 | 108 | 109 | ---- 110 | 111 | .. function:: relative_major(key) 112 | 113 | Return the relative major of a minor key. 114 | 115 | Example: 116 | 117 | >>> relative_major('a') 118 | 'C' 119 | 120 | 121 | ---- 122 | 123 | .. function:: relative_minor(key) 124 | 125 | Return the relative minor of a major key. 126 | 127 | Example: 128 | 129 | >>> relative_minor('C') 130 | 'a' 131 | 132 | ---- 133 | 134 | 135 | 136 | :doc:`Back to Index` 137 | -------------------------------------------------------------------------------- /doc/wiki/refMingusCoreMeter.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.core.meter 2 | 3 | ================= 4 | mingus.core.meter 5 | ================= 6 | 7 | Module for dealing with meters. 8 | 9 | A meter is represented by a tuple. 4/4 time would look like (4,4), 3/4 like 10 | (3,4), etc. 11 | 12 | 13 | 14 | ---- 15 | 16 | .. data:: common_time 17 | 18 | Attribute of type: tuple 19 | ``(4, 4)`` 20 | 21 | ---- 22 | 23 | .. data:: cut_time 24 | 25 | Attribute of type: tuple 26 | ``(2, 2)`` 27 | 28 | ---- 29 | 30 | .. function:: is_asymmetrical(meter) 31 | 32 | Return True if meter is an asymmetrical meter, False otherwise. 33 | 34 | Examples: 35 | 36 | >>> is_asymmetrical((3,4)) 37 | True 38 | >>> is_asymmetrical((4,4)) 39 | False 40 | 41 | 42 | ---- 43 | 44 | .. function:: is_compound(meter) 45 | 46 | Return True if meter is a compound meter, False otherwise. 47 | 48 | Examples: 49 | 50 | >>> is_compound((3,4)) 51 | False 52 | >>> is_compound((4,4)) 53 | False 54 | >>> is_compound((6,8)) 55 | True 56 | 57 | 58 | ---- 59 | 60 | .. function:: is_simple(meter) 61 | 62 | Return True if meter is a simple meter, False otherwise. 63 | 64 | Examples: 65 | 66 | >>> is_simple((3,4)) 67 | True 68 | >>> is_simple((4,4)) 69 | True 70 | 71 | 72 | ---- 73 | 74 | .. function:: is_valid(meter) 75 | 76 | Return True if meter is a valid tuple representation of a meter. 77 | 78 | Examples for meters are (3,4) for 3/4, (4,4) for 4/4, etc. 79 | 80 | 81 | ---- 82 | 83 | .. function:: valid_beat_duration(duration) 84 | 85 | Return True when log2(duration) is an integer. 86 | 87 | ---- 88 | 89 | 90 | 91 | :doc:`Back to Index` 92 | -------------------------------------------------------------------------------- /doc/wiki/refMingusCoreMt_exceptions.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.core.mt_exceptions 2 | 3 | ========================= 4 | mingus.core.mt_exceptions 5 | ========================= 6 | 7 | 8 | .. class:: Error 9 | 10 | 11 | .. attribute:: args 12 | 13 | Attribute of type: getset_descriptor 14 | ```` 15 | 16 | .. attribute:: message 17 | 18 | Attribute of type: getset_descriptor 19 | ```` 20 | 21 | .. class:: FingerError 22 | 23 | 24 | .. attribute:: args 25 | 26 | Attribute of type: getset_descriptor 27 | ```` 28 | 29 | .. attribute:: message 30 | 31 | Attribute of type: getset_descriptor 32 | ```` 33 | 34 | .. class:: FormatError 35 | 36 | 37 | .. attribute:: args 38 | 39 | Attribute of type: getset_descriptor 40 | ```` 41 | 42 | .. attribute:: message 43 | 44 | Attribute of type: getset_descriptor 45 | ```` 46 | 47 | .. class:: KeyError 48 | 49 | 50 | .. attribute:: args 51 | 52 | Attribute of type: getset_descriptor 53 | ```` 54 | 55 | .. attribute:: message 56 | 57 | Attribute of type: getset_descriptor 58 | ```` 59 | 60 | .. class:: NoteFormatError 61 | 62 | 63 | .. attribute:: args 64 | 65 | Attribute of type: getset_descriptor 66 | ```` 67 | 68 | .. attribute:: message 69 | 70 | Attribute of type: getset_descriptor 71 | ```` 72 | 73 | .. class:: RangeError 74 | 75 | 76 | .. attribute:: args 77 | 78 | Attribute of type: getset_descriptor 79 | ```` 80 | 81 | .. attribute:: message 82 | 83 | Attribute of type: getset_descriptor 84 | ```` 85 | ---- 86 | 87 | 88 | 89 | :doc:`Back to Index` 90 | -------------------------------------------------------------------------------- /doc/wiki/refMingusCoreNotes.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.core.notes 2 | 3 | ================= 4 | mingus.core.notes 5 | ================= 6 | 7 | Basic module for notes. 8 | 9 | This module is the foundation of the music theory package. 10 | 11 | It handles conversions from integers to notes and vice versa and thus 12 | enables simple calculations. 13 | 14 | 15 | 16 | ---- 17 | 18 | .. data:: fifths 19 | 20 | Attribute of type: list 21 | ``['F', 'C', 'G', 'D', 'A', 'E', 'B']`` 22 | 23 | ---- 24 | 25 | .. function:: augment(note) 26 | 27 | Augment a given note. 28 | 29 | Examples: 30 | 31 | >>> augment('C') 32 | 'C#' 33 | >>> augment('Cb') 34 | 'C' 35 | 36 | 37 | ---- 38 | 39 | .. function:: diminish(note) 40 | 41 | Diminish a given note. 42 | 43 | Examples: 44 | 45 | >>> diminish('C') 46 | 'Cb' 47 | >>> diminish('C#') 48 | 'C' 49 | 50 | 51 | ---- 52 | 53 | .. function:: int_to_note(note_int, accidentals=#) 54 | 55 | Convert integers in the range of 0-11 to notes in the form of C or C# 56 | or Db. 57 | 58 | Throw a RangeError exception if the note_int is not in the range 0-11. 59 | 60 | If not specified, sharps will be used. 61 | 62 | Examples: 63 | 64 | >>> int_to_note(0) 65 | 'C' 66 | >>> int_to_note(3) 67 | 'D#' 68 | >>> int_to_note(3, 'b') 69 | 'Eb' 70 | 71 | 72 | ---- 73 | 74 | .. function:: is_enharmonic(note1, note2) 75 | 76 | Test whether note1 and note2 are enharmonic, i.e. they sound the same. 77 | 78 | 79 | ---- 80 | 81 | .. function:: is_valid_note(note) 82 | 83 | Return True if note is in a recognised format. False if not. 84 | 85 | 86 | ---- 87 | 88 | .. function:: note_to_int(note) 89 | 90 | Convert notes in the form of C, C#, Cb, C##, etc. to an integer in the 91 | range of 0-11. 92 | 93 | Throw a NoteFormatError exception if the note format is not recognised. 94 | 95 | 96 | ---- 97 | 98 | .. function:: reduce_accidentals(note) 99 | 100 | Reduce any extra accidentals to proper notes. 101 | 102 | Example: 103 | 104 | >>> reduce_accidentals('C####') 105 | 'E' 106 | 107 | 108 | ---- 109 | 110 | .. function:: remove_redundant_accidentals(note) 111 | 112 | Remove redundant sharps and flats from the given note. 113 | 114 | Examples: 115 | 116 | >>> remove_redundant_accidentals('C##b') 117 | 'C#' 118 | >>> remove_redundant_accidentals('Eb##b') 119 | 'E' 120 | 121 | ---- 122 | 123 | 124 | 125 | :doc:`Back to Index` 126 | -------------------------------------------------------------------------------- /doc/wiki/refMingusExtraFft.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.extra.fft 2 | 3 | ================ 4 | mingus.extra.fft 5 | ================ 6 | 7 | Find the frequencies in raw audio data by using fast Fourier transformations 8 | (supplied by numpy). 9 | 10 | This module can also convert the found frequencies to Note objects. 11 | 12 | 13 | 14 | ---- 15 | 16 | .. data:: x 17 | 18 | Attribute of type: int 19 | ``128`` 20 | 21 | ---- 22 | 23 | .. function:: _fft(a, n=None, axis=-1) 24 | 25 | Compute the one-dimensional discrete Fourier Transform. 26 | 27 | This function computes the one-dimensional *n*-point discrete Fourier 28 | Transform (DFT) with the efficient Fast Fourier Transform (FFT) 29 | algorithm [CT]. 30 | 31 | Parameters 32 | ---------- 33 | a : array_like 34 | Input array, can be complex. 35 | n : int, optional 36 | Length of the transformed axis of the output. 37 | If `n` is smaller than the length of the input, the input is cropped. 38 | If it is larger, the input is padded with zeros. If `n` is not given, 39 | the length of the input along the axis specified by `axis` is used. 40 | axis : int, optional 41 | Axis over which to compute the FFT. If not given, the last axis is 42 | used. 43 | 44 | Returns 45 | ------- 46 | out : complex ndarray 47 | The truncated or zero-padded input, transformed along the axis 48 | indicated by `axis`, or the last one if `axis` is not specified. 49 | 50 | Raises 51 | ------ 52 | IndexError 53 | if `axes` is larger than the last axis of `a`. 54 | 55 | See Also 56 | -------- 57 | numpy.fft : for definition of the DFT and conventions used. 58 | ifft : The inverse of `fft`. 59 | fft2 : The two-dimensional FFT. 60 | fftn : The *n*-dimensional FFT. 61 | rfftn : The *n*-dimensional FFT of real input. 62 | fftfreq : Frequency bins for given FFT parameters. 63 | 64 | Notes 65 | ----- 66 | FFT (Fast Fourier Transform) refers to a way the discrete Fourier 67 | Transform (DFT) can be calculated efficiently, by using symmetries in the 68 | calculated terms. The symmetry is highest when `n` is a power of 2, and 69 | the transform is therefore most efficient for these sizes. 70 | 71 | The DFT is defined, with the conventions used in this implementation, in 72 | the documentation for the `numpy.fft` module. 73 | 74 | References 75 | ---------- 76 | .. [CT] Cooley, James W., and John W. Tukey, 1965, "An algorithm for the 77 | machine calculation of complex Fourier series," *Math. Comput.* 78 | 19: 297-301. 79 | 80 | Examples 81 | -------- 82 | 83 | >>> np.fft.fft(np.exp(2j * np.pi * np.arange(8) / 8)) 84 | array([ -3.44505240e-16 +1.14383329e-17j, 85 | 8.00000000e+00 -5.71092652e-15j, 86 | 2.33482938e-16 +1.22460635e-16j, 87 | 1.64863782e-15 +1.77635684e-15j, 88 | 9.95839695e-17 +2.33482938e-16j, 89 | 0.00000000e+00 +1.66837030e-15j, 90 | 1.14383329e-17 +1.22460635e-16j, 91 | -1.64863782e-15 +1.77635684e-15j]) 92 | 93 | >>> import matplotlib.pyplot as plt 94 | >>> t = np.arange(256) 95 | >>> sp = np.fft.fft(np.sin(t)) 96 | >>> freq = np.fft.fftfreq(t.shape[-1]) 97 | >>> plt.plot(freq, sp.real, freq, sp.imag) 98 | [, ] 99 | >>> plt.show() 100 | 101 | In this example, real input has an FFT which is Hermitian, i.e., symmetric 102 | in the real part and anti-symmetric in the imaginary part, as described in 103 | the `numpy.fft` documentation. 104 | 105 | 106 | ---- 107 | 108 | .. function:: _find_log_index(f) 109 | 110 | Look up the index of the frequency f in the frequency table. 111 | 112 | Return the nearest index. 113 | 114 | 115 | ---- 116 | 117 | .. function:: analyze_chunks(data, freq, bits, chunksize=512) 118 | 119 | Cut the one channel data in chunks and analyzes them separately. 120 | 121 | Making the chunksize a power of two works fastest. 122 | 123 | 124 | ---- 125 | 126 | .. function:: data_from_file(file) 127 | 128 | Return (first channel data, sample frequency, sample width) from a .wav 129 | file. 130 | 131 | 132 | ---- 133 | 134 | .. function:: find_Note(data, freq, bits) 135 | 136 | Get the frequencies, feed them to find_notes and the return the Note 137 | with the highest amplitude. 138 | 139 | 140 | ---- 141 | 142 | .. function:: find_frequencies(data, freq=44100, bits=16) 143 | 144 | Convert audio data into a frequency-amplitude table using fast fourier 145 | transformation. 146 | 147 | Return a list of tuples (frequency, amplitude). 148 | 149 | Data should only contain one channel of audio. 150 | 151 | 152 | ---- 153 | 154 | .. function:: find_melody(file=440_480_clean.wav, chunksize=512) 155 | 156 | Cut the sample into chunks and analyze each chunk. 157 | 158 | Return a list [(Note, chunks)] where chunks is the number of chunks 159 | where that note is the most dominant. 160 | 161 | If two consequent chunks turn out to return the same Note they are 162 | grouped together. 163 | 164 | This is an experimental function. 165 | 166 | 167 | ---- 168 | 169 | .. function:: find_notes(freqTable, maxNote=100) 170 | 171 | Convert the (frequencies, amplitude) list to a (Note, amplitude) list. 172 | 173 | ---- 174 | 175 | 176 | 177 | :doc:`Back to Index` 178 | -------------------------------------------------------------------------------- /doc/wiki/refMingusExtraLilypond.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.extra.lilypond 2 | 3 | ===================== 4 | mingus.extra.lilypond 5 | ===================== 6 | 7 | Functions to generate files in the LilyPond format. 8 | 9 | This allows you to create sheet music from some of the objects in 10 | mingus.containers. 11 | 12 | 13 | 14 | ---- 15 | 16 | .. function:: from_Bar(bar, showkey=True, showtime=True) 17 | 18 | Get a Bar object and return the LilyPond equivalent in a string. 19 | 20 | The showkey and showtime parameters can be set to determine whether the 21 | key and the time should be shown. 22 | 23 | 24 | ---- 25 | 26 | .. function:: from_Composition(composition) 27 | 28 | Return the LilyPond equivalent of a Composition in a string. 29 | 30 | 31 | ---- 32 | 33 | .. function:: from_Note(note, process_octaves=True, standalone=True) 34 | 35 | Get a Note object and return the LilyPond equivalent in a string. 36 | 37 | If process_octaves is set to False, all data regarding octaves will be 38 | ignored. If standalone is True, the result can be used by functions 39 | like to_png and will produce a valid output. The argument is mostly here 40 | to let from_NoteContainer make use of this function. 41 | 42 | 43 | ---- 44 | 45 | .. function:: from_NoteContainer(nc, duration=None, standalone=True) 46 | 47 | Get a NoteContainer object and return the LilyPond equivalent in a 48 | string. 49 | 50 | The second argument determining the duration of the NoteContainer is 51 | optional. When the standalone argument is True the result of this 52 | function can be used directly by functions like to_png. It is mostly 53 | here to be used by from_Bar. 54 | 55 | 56 | ---- 57 | 58 | .. function:: from_Suite(suite) 59 | 60 | 61 | ---- 62 | 63 | .. function:: from_Track(track) 64 | 65 | Process a Track object and return the LilyPond equivalent in a string. 66 | 67 | 68 | ---- 69 | 70 | .. function:: save_string_and_execute_LilyPond(ly_string, filename, command) 71 | 72 | A helper function for to_png and to_pdf. Should not be used directly. 73 | 74 | 75 | ---- 76 | 77 | .. function:: to_pdf(ly_string, filename) 78 | 79 | Save a string in LilyPond format to a PDF. 80 | 81 | LilyPond in the $PATH is needed. 82 | 83 | 84 | ---- 85 | 86 | .. function:: to_png(ly_string, filename) 87 | 88 | Save a string in LilyPond format to a PNG. 89 | 90 | LilyPond in the $PATH is needed. 91 | 92 | ---- 93 | 94 | 95 | 96 | :doc:`Back to Index` 97 | -------------------------------------------------------------------------------- /doc/wiki/refMingusExtraStringtuning.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.extra.StringTuning 2 | 3 | ========================= 4 | mingus.extra.StringTuning 5 | ========================= 6 | 7 | A class to store and work with tunings and fingerings. 8 | 9 | 10 | ---- 11 | 12 | .. function:: __init__(self, instrument, description, tuning) 13 | 14 | Create a new StringTuning instance. 15 | 16 | The instrument and description parameters should be strings; tuning 17 | should be a list of strings or a list of lists of strings that 18 | denote courses. 19 | 20 | See tunings.add_tuning for examples. 21 | 22 | 23 | ---- 24 | 25 | .. function:: count_courses(self) 26 | 27 | Return the average number of courses per string. 28 | 29 | 30 | ---- 31 | 32 | .. function:: count_strings(self) 33 | 34 | Return the number of strings. 35 | 36 | 37 | ---- 38 | 39 | .. function:: find_chord_fingering(self, notes, max_distance=4, maxfret=18, max_fingers=4, return_best_as_NoteContainer=False) 40 | 41 | Return a list of fret lists that are considered possible fingerings. 42 | 43 | This function only looks at and matches on the note _names_ so it 44 | does more than find_fingering. 45 | 46 | Example: 47 | 48 | >>> t = tunings.get_tuning('guitar', 'standard', 6, 1) 49 | >>> t.find_chord_fingering(NoteContainer().from_chord('Am')) 50 | [[0, 0, 2, 2, 1, 0], [0, 3, 2, 2, 1, 0], ......] 51 | 52 | 53 | ---- 54 | 55 | .. function:: find_fingering(self, notes, max_distance=4, not_strings=[]) 56 | 57 | Return a list [(string, fret)] of possible fingerings for 58 | 'notes'. 59 | 60 | The notes parameter should be a list of strings or Notes or a 61 | NoteContainer; max_distance denotes the maximum distance between 62 | frets; not_strings can be used to disclude certain strings and is 63 | used internally to recurse. 64 | 65 | Example: 66 | 67 | >>> t = tunings.StringTuning('test', 'test', ['A-3', 'E-4', 'A-5']) 68 | >>> t.find_fingering(['E-4', 'B-4']) 69 | [[(0, 7), (1, 7)], [(1, 0), (0, 14)]] 70 | 71 | 72 | ---- 73 | 74 | .. function:: find_frets(self, note, maxfret=24) 75 | 76 | Return a list with for each string the fret on which the note is 77 | played or None if it can't be played on that particular string. 78 | 79 | The maxfret parameter is the highest fret that can be played; note 80 | should either be a string or a Note object. 81 | 82 | Example: 83 | 84 | >>> t = tunings.StringTuning('test', 'test', ['A-3', 'E-4']) 85 | >>> t.find_frets(Note('C-4') 86 | [3, None] 87 | >>> t.find_frets(Note('A-4') 88 | [12, 5] 89 | 90 | 91 | ---- 92 | 93 | .. function:: find_note_names(self, notelist, string=0, maxfret=24) 94 | 95 | Return a list [(fret, notename)] in ascending order. 96 | 97 | Notelist should be a list of Notes, note-strings or a NoteContainer. 98 | 99 | Example: 100 | 101 | >>> t = tunings.StringTuning('test', 'test', ['A-3', 'A-4']) 102 | >>> t.find_note_names(['A', 'C', 'E'], 0, 12) 103 | [(0, 'E'), (5, 'A'), (8, 'C'), (12, 'E')] 104 | 105 | 106 | ---- 107 | 108 | .. function:: frets_to_NoteContainer(self, fingering) 109 | 110 | Convert a list such as returned by find_fret to a NoteContainer. 111 | 112 | 113 | ---- 114 | 115 | .. function:: get_Note(self, string=0, fret=0, maxfret=24) 116 | 117 | Return the Note on 'string', 'fret'. 118 | 119 | Throw a RangeError if either the fret or string is unplayable. 120 | 121 | Examples: 122 | 123 | >>> t = tunings.StringTuning('test', 'test', ['A-3', 'A-4']) 124 | >>> t,get_Note(0, 0) 125 | 'A-3' 126 | >>> t.get_Note(0, 1) 127 | 'A#-3' 128 | >>> t.get_Note(1, 0) 129 | 'A-4' 130 | 131 | ---- 132 | 133 | 134 | 135 | :doc:`Back to Index` 136 | -------------------------------------------------------------------------------- /doc/wiki/refMingusExtraTablature.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.extra.tablature 2 | 3 | ====================== 4 | mingus.extra.tablature 5 | ====================== 6 | 7 | Functions to convert mingus.containers to pretty ASCII tablature. 8 | 9 | 10 | ---- 11 | 12 | .. data:: default_tuning 13 | 14 | Attribute of type: mingus.extra.tunings.StringTuning 15 | ```` 16 | 17 | ---- 18 | 19 | .. function:: _get_qsize(tuning, width) 20 | 21 | Return a reasonable quarter note size for 'tuning' and 'width'. 22 | 23 | 24 | ---- 25 | 26 | .. function:: _get_width(maxwidth) 27 | 28 | Return the width of a single bar, when width of the page is given. 29 | 30 | 31 | ---- 32 | 33 | .. function:: add_headers(width=80, title=Untitled, subtitle=, author=, email=, description=, tunings=[]) 34 | 35 | Create a nice header in the form of a list of strings using the 36 | information that has been filled in. 37 | 38 | All arguments except 'width' and 'tunings' should be strings. 'width' 39 | should be an integer and 'tunings' a list of tunings representing the 40 | instruments. 41 | 42 | 43 | ---- 44 | 45 | .. function:: begin_track(tuning, padding=2) 46 | 47 | Helper function that builds the first few characters of every bar. 48 | 49 | 50 | ---- 51 | 52 | .. function:: from_Bar(bar, width=40, tuning=None, collapse=True) 53 | 54 | Convert a mingus.containers.Bar object to ASCII tablature. 55 | 56 | Throw a FingerError if no playable fingering can be found. 57 | 58 | 'tuning' should be a StringTuning object or None for the default tuning. 59 | If 'collapse' is False this will return a list of lines, if it's True 60 | all lines will be concatenated with a newline symbol. 61 | 62 | Use 'string' and 'fret' attributes on Notes to force certain fingerings. 63 | 64 | 65 | ---- 66 | 67 | .. function:: from_Composition(composition, width=80) 68 | 69 | Convert a mingus.containers.Composition to an ASCII tablature string. 70 | 71 | Automatically add an header based on the title, subtitle, author, e-mail 72 | and description attributes. An extra description of the piece can also 73 | be given. 74 | 75 | Tunings can be set by using the Track.instrument.tuning or Track.tuning 76 | attribute. 77 | 78 | 79 | ---- 80 | 81 | .. function:: from_Note(note, width=80, tuning=None) 82 | 83 | Return a string made out of ASCII tablature representing a Note object 84 | or note string. 85 | 86 | Throw a RangeError if a suitable fret can't be found. 87 | 88 | 'tuning' should be a StringTuning object or None for the default tuning. 89 | 90 | To force a certain fingering you can use a 'string' and 'fret' attribute 91 | on the Note. If the fingering is valid, it will get used instead of the 92 | default one. 93 | 94 | 95 | ---- 96 | 97 | .. function:: from_NoteContainer(notes, width=80, tuning=None) 98 | 99 | Return a string made out of ASCII tablature representing a 100 | NoteContainer object or list of note strings / Note objects. 101 | 102 | Throw a FingerError if no playable fingering can be found. 103 | 104 | 'tuning' should be a StringTuning object or None for the default tuning. 105 | 106 | To force a certain fingering you can use a 'string' and 'fret' attribute 107 | on one or more of the Notes. If the fingering is valid, it will get used 108 | instead of the default one. 109 | 110 | 111 | ---- 112 | 113 | .. function:: from_Suite(suite, maxwidth=80) 114 | 115 | Convert a mingus.containers.Suite to an ASCII tablature string, complete 116 | with headers. 117 | 118 | This function makes use of the Suite's title, subtitle, author, email 119 | and description attributes. 120 | 121 | 122 | ---- 123 | 124 | .. function:: from_Track(track, maxwidth=80, tuning=None) 125 | 126 | Convert a mingus.containers.Track object to an ASCII tablature string. 127 | 128 | 'tuning' should be set to a StringTuning object or to None to use the 129 | Track's tuning (or alternatively the default if the Track hasn't got its 130 | own tuning). 131 | 132 | 'string' and 'fret' attributes on Notes are taken into account. 133 | 134 | ---- 135 | 136 | 137 | 138 | :doc:`Back to Index` 139 | -------------------------------------------------------------------------------- /doc/wiki/refMingusMidiMidi_events.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.midi.midi_events 2 | 3 | ======================= 4 | mingus.midi.midi_events 5 | ======================= 6 | 7 | 8 | ---- 9 | 10 | .. data:: BALANCE 11 | 12 | Attribute of type: int 13 | ``8`` 14 | 15 | ---- 16 | 17 | .. data:: BANK_SELECT 18 | 19 | Attribute of type: int 20 | ``0`` 21 | 22 | ---- 23 | 24 | .. data:: BREATH_CONTROLLER 25 | 26 | Attribute of type: int 27 | ``2`` 28 | 29 | ---- 30 | 31 | .. data:: CHANNEL_AFTERTOUCH 32 | 33 | Attribute of type: int 34 | ``13`` 35 | 36 | ---- 37 | 38 | .. data:: CONTROLLER 39 | 40 | Attribute of type: int 41 | ``11`` 42 | 43 | ---- 44 | 45 | .. data:: COPYRIGHT_NOTICE 46 | 47 | Attribute of type: str 48 | ``'\x02'`` 49 | 50 | ---- 51 | 52 | .. data:: CUE_POINT 53 | 54 | Attribute of type: str 55 | ``'\x07'`` 56 | 57 | ---- 58 | 59 | .. data:: DATA_ENTRY_MSB 60 | 61 | Attribute of type: int 62 | ``6`` 63 | 64 | ---- 65 | 66 | .. data:: EFFECT_CONTROL_1 67 | 68 | Attribute of type: int 69 | ``12`` 70 | 71 | ---- 72 | 73 | .. data:: EFFECT_CONTROL_2 74 | 75 | Attribute of type: int 76 | ``13`` 77 | 78 | ---- 79 | 80 | .. data:: END_OF_TRACK 81 | 82 | Attribute of type: str 83 | ``'/'`` 84 | 85 | ---- 86 | 87 | .. data:: EXPRESSION_CONTROLLER 88 | 89 | Attribute of type: int 90 | ``11`` 91 | 92 | ---- 93 | 94 | .. data:: FILE_HEADER 95 | 96 | Attribute of type: str 97 | ``'MThd'`` 98 | 99 | ---- 100 | 101 | .. data:: FOOT_CONTROLLER 102 | 103 | Attribute of type: int 104 | ``4`` 105 | 106 | ---- 107 | 108 | .. data:: INSTRUMENT_NAME 109 | 110 | Attribute of type: str 111 | ``'\x04'`` 112 | 113 | ---- 114 | 115 | .. data:: KEY_SIGNATURE 116 | 117 | Attribute of type: str 118 | ``'Y'`` 119 | 120 | ---- 121 | 122 | .. data:: LYRICS 123 | 124 | Attribute of type: str 125 | ``'\x05'`` 126 | 127 | ---- 128 | 129 | .. data:: MAIN_VOLUME 130 | 131 | Attribute of type: int 132 | ``7`` 133 | 134 | ---- 135 | 136 | .. data:: MARKER 137 | 138 | Attribute of type: str 139 | ``'\x06'`` 140 | 141 | ---- 142 | 143 | .. data:: META_EVENT 144 | 145 | Attribute of type: str 146 | ``'\xff'`` 147 | 148 | ---- 149 | 150 | .. data:: MIDI_CHANNEL_PREFIX 151 | 152 | Attribute of type: str 153 | ``' '`` 154 | 155 | ---- 156 | 157 | .. data:: MODULATION 158 | 159 | Attribute of type: int 160 | ``1`` 161 | 162 | ---- 163 | 164 | .. data:: NOTE_AFTERTOUCH 165 | 166 | Attribute of type: int 167 | ``10`` 168 | 169 | ---- 170 | 171 | .. data:: NOTE_OFF 172 | 173 | Attribute of type: int 174 | ``8`` 175 | 176 | ---- 177 | 178 | .. data:: NOTE_ON 179 | 180 | Attribute of type: int 181 | ``9`` 182 | 183 | ---- 184 | 185 | .. data:: PAN 186 | 187 | Attribute of type: int 188 | ``10`` 189 | 190 | ---- 191 | 192 | .. data:: PITCH_BEND 193 | 194 | Attribute of type: int 195 | ``14`` 196 | 197 | ---- 198 | 199 | .. data:: PORTAMENTO_TIME 200 | 201 | Attribute of type: int 202 | ``5`` 203 | 204 | ---- 205 | 206 | .. data:: PROGRAM_CHANGE 207 | 208 | Attribute of type: int 209 | ``12`` 210 | 211 | ---- 212 | 213 | .. data:: SEQUENCE_NUMBER 214 | 215 | Attribute of type: str 216 | ``'\x00'`` 217 | 218 | ---- 219 | 220 | .. data:: SET_TEMPO 221 | 222 | Attribute of type: str 223 | ``'Q'`` 224 | 225 | ---- 226 | 227 | .. data:: SMPTE_OFFSET 228 | 229 | Attribute of type: str 230 | ``'T'`` 231 | 232 | ---- 233 | 234 | .. data:: TEXT_EVENT 235 | 236 | Attribute of type: str 237 | ``'\x01'`` 238 | 239 | ---- 240 | 241 | .. data:: TIME_SIGNATURE 242 | 243 | Attribute of type: str 244 | ``'X'`` 245 | 246 | ---- 247 | 248 | .. data:: TRACK_HEADER 249 | 250 | Attribute of type: str 251 | ``'MTrk'`` 252 | 253 | ---- 254 | 255 | .. data:: TRACK_NAME 256 | 257 | Attribute of type: str 258 | ``'\x03'`` 259 | ---- 260 | 261 | 262 | 263 | :doc:`Back to Index` 264 | -------------------------------------------------------------------------------- /doc/wiki/refMingusMidiMidi_file_in.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.midi.midi_file_in 2 | 3 | ======================== 4 | mingus.midi.midi_file_in 5 | ======================== 6 | 7 | Read a MIDI file and convert it into mingus.containers objects. 8 | 9 | 10 | .. class:: FormatError 11 | 12 | 13 | .. attribute:: args 14 | 15 | Attribute of type: getset_descriptor 16 | ```` 17 | 18 | .. attribute:: message 19 | 20 | Attribute of type: getset_descriptor 21 | ```` 22 | 23 | .. class:: HeaderError 24 | 25 | 26 | .. attribute:: args 27 | 28 | Attribute of type: getset_descriptor 29 | ```` 30 | 31 | .. attribute:: message 32 | 33 | Attribute of type: getset_descriptor 34 | ```` 35 | 36 | .. class:: MidiFile 37 | 38 | 39 | .. method:: MIDI_to_Composition(self, file) 40 | 41 | 42 | .. attribute:: bpm 43 | 44 | Attribute of type: int 45 | ``120`` 46 | 47 | .. attribute:: bytes_read 48 | 49 | Attribute of type: int 50 | ``0`` 51 | 52 | .. method:: bytes_to_int(self, bytes) 53 | 54 | 55 | .. attribute:: meter 56 | 57 | Attribute of type: tuple 58 | ``(4, 4)`` 59 | 60 | .. method:: parse_midi_event(self, fp) 61 | 62 | Parse a MIDI event. 63 | 64 | Return a dictionary and the number of bytes read. 65 | 66 | 67 | .. method:: parse_midi_file(self, file) 68 | 69 | Parse a MIDI file. 70 | 71 | Return the header -as a tuple containing respectively the MIDI 72 | format, the number of tracks and the time division-, the parsed 73 | track data and the number of bytes read. 74 | 75 | 76 | .. method:: parse_midi_file_header(self, fp) 77 | 78 | Read the header of a MIDI file and return a tuple containing the 79 | format type, number of tracks and parsed time division information. 80 | 81 | 82 | .. method:: parse_time_division(self, bytes) 83 | 84 | Parse the time division found in the header of a MIDI file and 85 | return a dictionary with the boolean fps set to indicate whether to 86 | use frames per second or ticks per beat. 87 | 88 | If fps is True, the values SMPTE_frames and clock_ticks will also be 89 | set. If fps is False, ticks_per_beat will hold the value. 90 | 91 | 92 | .. method:: parse_track(self, fp) 93 | 94 | Parse a MIDI track from its header to its events. 95 | 96 | Return a list of events and the number of bytes that were read. 97 | 98 | 99 | .. method:: parse_track_header(self, fp) 100 | 101 | Return the size of the track chunk. 102 | 103 | 104 | .. method:: parse_varbyte_as_int(self, fp, return_bytes_read=True) 105 | 106 | Read a variable length byte from the file and return the 107 | corresponding integer. 108 | 109 | 110 | .. class:: TimeDivisionError 111 | 112 | 113 | .. attribute:: args 114 | 115 | Attribute of type: getset_descriptor 116 | ```` 117 | 118 | .. attribute:: message 119 | 120 | Attribute of type: getset_descriptor 121 | ```` 122 | 123 | ---- 124 | 125 | .. function:: MIDI_to_Composition(file) 126 | 127 | Convert a MIDI file to a mingus.containers.Composition and return it 128 | in a tuple with the last used tempo in beats per minute (this will 129 | change in the future). 130 | 131 | This function can raise all kinds of exceptions (IOError, HeaderError, 132 | TimeDivisionError, FormatError), so be sure to try and catch. 133 | 134 | ---- 135 | 136 | 137 | 138 | :doc:`Back to Index` 139 | -------------------------------------------------------------------------------- /doc/wiki/refMingusMidiMidi_file_out.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.midi.midi_file_out 2 | 3 | ========================= 4 | mingus.midi.midi_file_out 5 | ========================= 6 | 7 | Functions that can generate MIDI files from the objects in 8 | mingus.containers. 9 | 10 | 11 | .. class:: MidiFile 12 | 13 | 14 | .. method:: __init__(self, tracks=[]) 15 | 16 | 17 | .. method:: get_midi_data(self) 18 | 19 | Collect and return the raw, binary MIDI data from the tracks. 20 | 21 | 22 | .. method:: header(self) 23 | 24 | Return a header for type 1 MIDI file. 25 | 26 | 27 | .. method:: reset(self) 28 | 29 | Reset every track. 30 | 31 | 32 | .. attribute:: time_division 33 | 34 | Attribute of type: str 35 | ``'\x00H'`` 36 | 37 | .. attribute:: tracks 38 | 39 | Attribute of type: list 40 | ``[]`` 41 | 42 | .. method:: write_file(self, file, verbose=False) 43 | 44 | Collect the data from get_midi_data and write to file. 45 | 46 | 47 | ---- 48 | 49 | .. function:: write_Bar(file, bar, bpm=120, repeat=0, verbose=False) 50 | 51 | Write a mingus.Bar to a MIDI file. 52 | 53 | Both the key and the meter are written to the file as well. 54 | 55 | 56 | ---- 57 | 58 | .. function:: write_Composition(file, composition, bpm=120, repeat=0, verbose=False) 59 | 60 | Write a mingus.Composition to a MIDI file. 61 | 62 | 63 | ---- 64 | 65 | .. function:: write_Note(file, note, bpm=120, repeat=0, verbose=False) 66 | 67 | Expect a Note object from mingus.containers and save it into a MIDI 68 | file, specified in file. 69 | 70 | You can set the velocity and channel in Note.velocity and Note.channel. 71 | 72 | 73 | ---- 74 | 75 | .. function:: write_NoteContainer(file, notecontainer, bpm=120, repeat=0, verbose=False) 76 | 77 | Write a mingus.NoteContainer to a MIDI file. 78 | 79 | 80 | ---- 81 | 82 | .. function:: write_Track(file, track, bpm=120, repeat=0, verbose=False) 83 | 84 | Write a mingus.Track to a MIDI file. 85 | 86 | Write the name to the file and set the instrument if the instrument has 87 | the attribute instrument_nr, which represents the MIDI instrument 88 | number. The class MidiInstrument in mingus.containers.Instrument has 89 | this attribute by default. 90 | 91 | ---- 92 | 93 | 94 | 95 | :doc:`Back to Index` 96 | -------------------------------------------------------------------------------- /doc/wiki/refMingusMidiSequencer.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.midi.sequencer 2 | 3 | ===================== 4 | mingus.midi.sequencer 5 | ===================== 6 | 7 | A general purpose sequencer for the objects in mingus.containers. 8 | 9 | You can use the Sequencer object either by creating a subclass and 10 | implementing some of the events (init, play_event, stop_event, cc_event, 11 | instr_event) or by attaching observer objects via 'attach' and catching the 12 | messages in the notify(msg_type, param_dict) function of your object. 13 | 14 | See SequencerObserver for a pre made, easy to extend base class that can be 15 | attached to the Sequencer. 16 | 17 | 18 | 19 | .. class:: Sequencer 20 | 21 | 22 | .. attribute:: MSG_CC 23 | 24 | Attribute of type: int 25 | ``2`` 26 | 27 | .. attribute:: MSG_INSTR 28 | 29 | Attribute of type: int 30 | ``3`` 31 | 32 | .. attribute:: MSG_PLAY_BAR 33 | 34 | Attribute of type: int 35 | ``9`` 36 | 37 | .. attribute:: MSG_PLAY_BARS 38 | 39 | Attribute of type: int 40 | ``10`` 41 | 42 | .. attribute:: MSG_PLAY_COMPOSITION 43 | 44 | Attribute of type: int 45 | ``13`` 46 | 47 | .. attribute:: MSG_PLAY_INT 48 | 49 | Attribute of type: int 50 | ``0`` 51 | 52 | .. attribute:: MSG_PLAY_NC 53 | 54 | Attribute of type: int 55 | ``7`` 56 | 57 | .. attribute:: MSG_PLAY_NOTE 58 | 59 | Attribute of type: int 60 | ``5`` 61 | 62 | .. attribute:: MSG_PLAY_TRACK 63 | 64 | Attribute of type: int 65 | ``11`` 66 | 67 | .. attribute:: MSG_PLAY_TRACKS 68 | 69 | Attribute of type: int 70 | ``12`` 71 | 72 | .. attribute:: MSG_SLEEP 73 | 74 | Attribute of type: int 75 | ``4`` 76 | 77 | .. attribute:: MSG_STOP_INT 78 | 79 | Attribute of type: int 80 | ``1`` 81 | 82 | .. attribute:: MSG_STOP_NC 83 | 84 | Attribute of type: int 85 | ``8`` 86 | 87 | .. attribute:: MSG_STOP_NOTE 88 | 89 | Attribute of type: int 90 | ``6`` 91 | 92 | .. method:: __init__(self) 93 | 94 | 95 | .. method:: attach(self, listener) 96 | 97 | Attach an object that should be notified of events. 98 | 99 | The object should have a notify(msg_type, param_dict) function. 100 | 101 | 102 | .. method:: cc_event(self, channel, control, value) 103 | 104 | 105 | .. method:: control_change(self, channel, control, value) 106 | 107 | Send a control change message. 108 | 109 | See the MIDI specification for more information. 110 | 111 | 112 | .. method:: detach(self, listener) 113 | 114 | Detach a listening object so that it won't receive any events 115 | anymore. 116 | 117 | 118 | .. method:: init(self) 119 | 120 | 121 | .. method:: instr_event(self, channel, instr, bank) 122 | 123 | 124 | .. method:: main_volume(self, channel, value) 125 | 126 | Set the main volume. 127 | 128 | 129 | .. method:: modulation(self, channel, value) 130 | 131 | Set the modulation. 132 | 133 | 134 | .. method:: notify_listeners(self, msg_type, params) 135 | 136 | Send a message to all the observers. 137 | 138 | 139 | .. attribute:: output 140 | 141 | Attribute of type: NoneType 142 | ``None`` 143 | 144 | .. method:: pan(self, channel, value) 145 | 146 | Set the panning. 147 | 148 | 149 | .. method:: play_Bar(self, bar, channel=1, bpm=120) 150 | 151 | Play a Bar object. 152 | 153 | Return a dictionary with the bpm lemma set on success, an empty dict 154 | on some kind of failure. 155 | 156 | The tempo can be changed by setting the bpm attribute on a 157 | NoteContainer. 158 | 159 | 160 | .. method:: play_Bars(self, bars, channels, bpm=120) 161 | 162 | Play several bars (a list of Bar objects) at the same time. 163 | 164 | A list of channels should also be provided. The tempo can be changed 165 | by providing one or more of the NoteContainers with a bpm argument. 166 | 167 | 168 | .. method:: play_Composition(self, composition, channels=None, bpm=120) 169 | 170 | Play a Composition object. 171 | 172 | 173 | .. method:: play_Note(self, note, channel=1, velocity=100) 174 | 175 | Play a Note object on a channel with a velocity[0-127]. 176 | 177 | You can either specify the velocity and channel here as arguments or 178 | you can set the Note.velocity and Note.channel attributes, which 179 | will take presedence over the function arguments. 180 | 181 | 182 | .. method:: play_NoteContainer(self, nc, channel=1, velocity=100) 183 | 184 | Play the Notes in the NoteContainer nc. 185 | 186 | 187 | .. method:: play_Track(self, track, channel=1, bpm=120) 188 | 189 | Play a Track object. 190 | 191 | 192 | .. method:: play_Tracks(self, tracks, channels, bpm=120) 193 | 194 | Play a list of Tracks. 195 | 196 | If an instance of MidiInstrument is used then the instrument will be 197 | set automatically. 198 | 199 | 200 | .. method:: play_event(self, note, channel, velocity) 201 | 202 | 203 | .. method:: set_instrument(self, channel, instr, bank=0) 204 | 205 | Set the channel to the instrument _instr_. 206 | 207 | 208 | .. method:: sleep(self, seconds) 209 | 210 | 211 | .. method:: stop_Note(self, note, channel=1) 212 | 213 | Stop a note on a channel. 214 | 215 | If Note.channel is set, it will take presedence over the channel 216 | argument given here. 217 | 218 | 219 | .. method:: stop_NoteContainer(self, nc, channel=1) 220 | 221 | Stop playing the notes in NoteContainer nc. 222 | 223 | 224 | .. method:: stop_event(self, note, channel) 225 | 226 | 227 | .. method:: stop_everything(self) 228 | 229 | Stop all the notes on all channels. 230 | 231 | ---- 232 | 233 | 234 | 235 | :doc:`Back to Index` 236 | -------------------------------------------------------------------------------- /doc/wiki/refMingusMidiSequencer_observer.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.midi.sequencer_observer 2 | 3 | ============================== 4 | mingus.midi.sequencer_observer 5 | ============================== 6 | 7 | Provides an easy to extend base class that can be used to observe a 8 | Sequencer. 9 | 10 | Each time a Sequencer starts playing a new Note, Bar, w/e, an event is 11 | fired; this SequencerObserver intercepts the event messages and calls the 12 | proper function so you only have to implement the functions for the events 13 | you need to see. 14 | 15 | 16 | 17 | .. class:: SequencerObserver 18 | 19 | 20 | .. method:: cc_event(self, channel, control, value) 21 | 22 | 23 | .. method:: instr_event(self, channel, instr, bank) 24 | 25 | 26 | .. method:: notify(self, msg_type, params) 27 | 28 | 29 | .. method:: play_Bar(self, bar, channel, bpm) 30 | 31 | 32 | .. method:: play_Bars(self, bars, channels, bpm) 33 | 34 | 35 | .. method:: play_Composition(self, composition, channels, bpm) 36 | 37 | 38 | .. method:: play_Note(self, note, channel, velocity) 39 | 40 | 41 | .. method:: play_NoteContainer(self, notes, channel) 42 | 43 | 44 | .. method:: play_Track(self, track, channel, bpm) 45 | 46 | 47 | .. method:: play_Tracks(self, tracks, channels, bpm) 48 | 49 | 50 | .. method:: play_int_note_event(self, int_note, channel, velocity) 51 | 52 | 53 | .. method:: sleep(self, seconds) 54 | 55 | 56 | .. method:: stop_Note(self, note, channel) 57 | 58 | 59 | .. method:: stop_NoteContainer(self, notes, channel) 60 | 61 | 62 | .. method:: stop_int_note_event(self, int_note, channel) 63 | 64 | ---- 65 | 66 | 67 | 68 | :doc:`Back to Index` 69 | -------------------------------------------------------------------------------- /doc/wiki/refMingusMidiSequencerobserver.rst: -------------------------------------------------------------------------------- 1 | .. module:: mingus.midi.SequencerObserver 2 | 3 | ============================= 4 | mingus.midi.SequencerObserver 5 | ============================= 6 | 7 | An easy to extend base class that can be used to observe a Sequencer. 8 | 9 | Each time a Sequencer starts playing a new Note, Bar, w/e, an event is 10 | fired; this SequencerObserver intercepts the event messages and calls 11 | the proper function so you only have to implement the functions for the 12 | events you need to see. 13 | 14 | 15 | 16 | ---- 17 | 18 | .. function:: cc_event(self, channel, control, value) 19 | 20 | 21 | ---- 22 | 23 | .. function:: instr_event(self, channel, instr, bank) 24 | 25 | 26 | ---- 27 | 28 | .. function:: notify(self, msg_type, params) 29 | 30 | 31 | ---- 32 | 33 | .. function:: play_Bar(self, bar, channel, bpm) 34 | 35 | 36 | ---- 37 | 38 | .. function:: play_Bars(self, bars, channels, bpm) 39 | 40 | 41 | ---- 42 | 43 | .. function:: play_Composition(self, composition, channels, bpm) 44 | 45 | 46 | ---- 47 | 48 | .. function:: play_Note(self, note, channel, velocity) 49 | 50 | 51 | ---- 52 | 53 | .. function:: play_NoteContainer(self, notes, channel) 54 | 55 | 56 | ---- 57 | 58 | .. function:: play_Track(self, track, channel, bpm) 59 | 60 | 61 | ---- 62 | 63 | .. function:: play_Tracks(self, tracks, channels, bpm) 64 | 65 | 66 | ---- 67 | 68 | .. function:: play_int_note_event(self, int_note, channel, velocity) 69 | 70 | 71 | ---- 72 | 73 | .. function:: sleep(self, seconds) 74 | 75 | 76 | ---- 77 | 78 | .. function:: stop_Note(self, note, channel) 79 | 80 | 81 | ---- 82 | 83 | .. function:: stop_NoteContainer(self, notes, channel) 84 | 85 | 86 | ---- 87 | 88 | .. function:: stop_int_note_event(self, int_note, channel) 89 | 90 | ---- 91 | 92 | 93 | 94 | :doc:`Back to Index` 95 | -------------------------------------------------------------------------------- /doc/wiki/tutorialCompositionModule.rst: -------------------------------------------------------------------------------- 1 | Tutorial 6 - Composition 2 | ======================== 3 | 4 | A Composition can be used to organize Tracks and to add some metadata such as `title`, `subtitle` and `author`. 5 | 6 | 7 | >>> from mingus.containers import Composition 8 | 9 | 10 | 11 | 12 | ---- 13 | 14 | 15 | Creating Compositions 16 | --------------------- 17 | 18 | The Composition class takes no argument to create: 19 | 20 | 21 | 22 | >>> c= Composition() 23 | 24 | 25 | 26 | 27 | Setting Attributes 28 | ------------------ 29 | 30 | The `author`, `email`, `title` and `subtitle` attributes can be easily handled with the functions `set_author` and `set_title`: 31 | 32 | 33 | 34 | >>> c = Composition() 35 | >>> c.set_author('Author', 'author@email.com') 36 | >>> c.set_title('First Mingus Composition') 37 | 38 | 39 | 40 | 41 | 42 | ---- 43 | 44 | 45 | This should sound pretty familiar by now: 46 | 47 | Adding Tracks 48 | ------------- 49 | 50 | 51 | 52 | >>> c = Composition() 53 | >>> t = Track() 54 | >>> c.add_track(t) 55 | 56 | 57 | 58 | Adding Notes 59 | ------------ 60 | 61 | This might seem a little strange, and you probably won't use it much. 62 | 63 | 64 | 65 | >>> c = Composition() 66 | >>> c.add_note("C") 67 | 68 | 69 | 70 | The note gets added to the tracks in `Composition.selected_tracks` which is automatically set when you use `add_track`, but which you can also use yourself. 71 | 72 | 73 | The Overloaded '+' Operator 74 | --------------------------- 75 | 76 | This operator accepts Notes, note strings, NoteContainers, Bars and Tracks. 77 | 78 | 79 | 80 | >>> c = Composition() 81 | >>> c + "C" 82 | 83 | 84 | 85 | List Notation 86 | ------------- 87 | 88 | 89 | >>> c = Composition() 90 | >>> len(c) 91 | 0 92 | >>> c + Track() 93 | >>> c[0] = Track 94 | 95 | 96 | 97 | ---- 98 | 99 | 100 | You can learn more about `mingus.containers.Composition `_ in the reference section. 101 | 102 | * `Tutorial 1 - The Note Class `_ 103 | * `Tutorial 2 - NoteContainers `_ 104 | * `Tutorial 3 - Bars `_ 105 | * `Tutorial 4 - Instruments `_ 106 | * `Tutorial 5 - Tracks `_ 107 | * Tutorial 6 - Compositions 108 | * `Tutorial 7 - Suites `_ 109 | * :doc:`Back to Index ` 110 | -------------------------------------------------------------------------------- /doc/wiki/tutorialCore.rst: -------------------------------------------------------------------------------- 1 | Tutorial 8 - Working the Core 2 | ================================== 3 | 4 | `modules.core` allows you to build all kinds of applications. The last tutorial in this section presents you with some information that might help you build software with this subpackage. 5 | 6 | 7 | >>> from mingus.core import * 8 | 9 | 10 | 11 | This will import the modules discussed in the previous tutorials in the current namespace. So `notes`, `diatonic`, `intervals`, `chords`, `scales`, `value`, `meter` and `progressions` are all directly accessible. 12 | 13 | 14 | ---- 15 | 16 | 17 | Module Dependencies 18 | ------------------- 19 | 20 | .. image:: core.1.png 21 | 22 | 23 | ---- 24 | 25 | 26 | 27 | You can learn everything about mingus.core in the reference section. 28 | 29 | * `Move on the next set of tutorials `_ 30 | * :doc:`Back to Index ` 31 | -------------------------------------------------------------------------------- /doc/wiki/tutorialDiatonic.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 - Keys and the Diatonic Scale 2 | ======================================== 3 | 4 | The diatonic module is another fundamental module providing support for keys and the diatonic scale. Without this module, mingus would be utterly useless. Let's open up a python shell and start exploring. 5 | 6 | 7 | >>> import core.diatonic as diatonic 8 | 9 | 10 | 11 | ---- 12 | 13 | 14 | Keys 15 | ---- 16 | 17 | As we have seen in the previous tutorial, mingus accepts some funky syntax (eg. 'C####bbb#b'). While this is fine, it's normally not really helpful, especially not when talking about keys and scales. This module defines a list of basic notes (based on the circle of fifths): 18 | 19 | 20 | >>> diatonic.basic_keys 21 | ['Gb', 'Db', 'Ab', 'Eb', 'Bb', 'F', 'C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#', 'G#', 'D#', 'A#'] 22 | 23 | 24 | Although the following functions will still work with the strange syntax, I'd advise you -for your own sanity- not to indulge in them. 25 | 26 | 27 | ---- 28 | 29 | 30 | The Notes in a Key 31 | ------------------ 32 | 33 | 34 | To get the notes in a certain key, you can use `diatonic.get_notes(note)`. This method returns a list of notes, starting with the tonic. 35 | 36 | 37 | 38 | >>> diatonic.get_notes("C") 39 | ["C", "D", "E", "F", "G", "A", "B"] 40 | 41 | 42 | 43 | If you were not completely sure what a key was before, it should now be pretty clear. The key of C consists of all the white notes, which have a certain number of half note steps between them. If we now want the notes in the key of E, we can take the same steps, but this time starting on 'E' instead of 'C'. (See exercise 1). 44 | 45 | 46 | >>> diatonic.get_notes("E") 47 | ["E", "F#", "G#", "A", "B", "C#", "D#"] 48 | >>> diatonic.get_notes("Bb") 49 | ["Bb", "C", "D", "Eb", "F", "G", "A"] 50 | 51 | 52 | 53 | 54 | 55 | ---- 56 | 57 | 58 | A Better Integer to Note Converter 59 | ---------------------------------- 60 | 61 | Remember how poorly a theoretic job `notes.int_to_note(int)` did? `notes.int_to_note` would always convert 10 to A#, regardless of what key you're in. This fact becomes really obvious when you are playing in Bb. A better function would pay attention to the key as well; we can do that now: 62 | 63 | 64 | 65 | >>> diatonic.int_to_note(10, "C") 66 | 'A#' 67 | >>> diatonic.int_to_note(10, "F") 68 | 'Bb' 69 | >>> diatonic.int_to_note(11, "C") 70 | 'B' 71 | >>> diatonic.int_to_note(11, "Gb") 72 | 'Cb' 73 | 74 | 75 | 76 | 77 | ---- 78 | 79 | 80 | Exercises 81 | --------- 82 | 83 | * Write a program that lets the user input a key, get the notes in the key and print the half note steps between the notes. What do you notice when you ask for different keys? 84 | * For every note in `basic_keys`: Convert the numbers 0-11 using `diatonic.int_to_note` and `notes.int_to_note`. If the values are different, output the values, the number and the key to screen. 85 | 86 | 87 | ---- 88 | 89 | 90 | You can learn more about `mingus.core.diatonic `_ in the reference section 91 | 92 | * `Tutorial 1 - Working with Notes `_ 93 | * Tutorial 2 - Keys and the Diatonic Scale 94 | * `Tutorial 3 - Intervals `_ 95 | * :doc:`Back to Index ` 96 | -------------------------------------------------------------------------------- /doc/wiki/tutorialExtraLilypond.rst: -------------------------------------------------------------------------------- 1 | Tutorial 1 - Generating Sheet Music with LilyPond 2 | ================================================= 3 | 4 | The LilyPond module provides some methods to help you generate files in the LilyPond format. This allows you to create sheet music from some of the objects in mingus.containers. 5 | 6 | 7 | >>> import mingus.extra.lilypond as LilyPond 8 | 9 | 10 | 11 | 12 | ---- 13 | 14 | 15 | Generate LilyPond Strings 16 | ------------------------- 17 | 18 | LilyPond creates sheet music from files formatted in the LilyPond format. This module can convert instances of the `mingus.containers` module to formatted LilyPond strings. The functions `from_Note`, `from_NoteContainer`, `from_Bar`, `from_Track`, `from_Composition` and `from_Suite` can all be used to do that job. We will look at one simple example, to find out more about the respective functions and their arguments, you can check the [refMingusExtraLilypond reference section]. 19 | 20 | 21 | 22 | >>> b = Bar() 23 | >>> b + "C" 24 | >>> b + "E" 25 | >>> b + "G" 26 | >>> b + "B" 27 | >>> LilyPond.from_Bar(b) 28 | "{ \\time 4/4 \\key c \\major c'4 e'4 g'4 b'4 }" 29 | 30 | 31 | 32 | ---- 33 | 34 | 35 | Generating Files from LilyPond Strings 36 | -------------------------------------- 37 | 38 | To do something useful with the strings generated in the previous section, we can use the `to_png` and `to_pdf` functions. This does assume that you have LilyPond installed and in your $PATH. 39 | 40 | 41 | 42 | >>> b = Bar() 43 | >>> b + "C" 44 | >>> b + "E" 45 | >>> b + "G" 46 | >>> b + "B" 47 | >>> bar = LilyPond.from_Bar(b) 48 | >>> LilyPond.to_png(bar, "my_first_bar") 49 | 50 | 51 | .. image:: lpexample.png 52 | 53 | 54 | ---- 55 | 56 | * :doc:`Back to Index ` 57 | -------------------------------------------------------------------------------- /doc/wiki/tutorialFluidsynth.rst: -------------------------------------------------------------------------------- 1 | Tutorial 1 - Playing Containers with FluidSynth 2 | =============================================== 3 | 4 | `FluidSynth` is a MIDI synthesizer which uses SoundFont (.SF2) files to generate audio. To work with this module, you'll need the FluidSynth library (usually packaged with the stand-alone program) and a nice instrument collection (look here: http://www.hammersound.net, go to Sounds -> Soundfont Library -> Collections). 5 | 6 | 7 | >>> from mingus.midi import fluidsynth 8 | 9 | 10 | 11 | 12 | ---- 13 | 14 | 15 | Loading a SoundFont 16 | ------------------- 17 | 18 | To load the SoundFont and initialize FluidSynth we'll only have to call `init`. 19 | 20 | 21 | >>> fluidsynth.init("soundfont.SF2") 22 | 23 | 24 | You can give an optional second argument to specify a driver (one of 'alsa', 'oss', 'jack', 'portaudio', 'sndmgr', 'coreaudio' or 'Direct Sound'), otherwise the default driver for the system will be used. 25 | 26 | 27 | >>> fluidsynth.init("soundfont.SF2", "alsa") 28 | 29 | 30 | 31 | ---- 32 | 33 | 34 | Playing mingus.containers Objects 35 | --------------------------------- 36 | 37 | play_Note 38 | ^^^^^^^^^ 39 | 40 | `play_Note(note, channel = 1, velocity = 100)` converts the given Note object to a midi `note on` command on `channel`. The velocity (0-127) stands for the speed with which the notes are hit. This roughly translates to volume. 41 | 42 | 43 | >>> fluidsynth.play_Note(Note("C-5")) 44 | True 45 | >>> fluidsynth.play_Note(Note("E-5")) 46 | True 47 | 48 | 49 | The channel and velocity can be set as Note attributes as well. If that's the case those values take presedence over the ones given here as function arguments. 50 | 51 | 52 | >>> n = Note("C-5") 53 | >>> n.channel = 5 54 | >>> n.velocity = 50 55 | >>> fluidsynth.play_Note(n) 56 | True 57 | 58 | 59 | stop_Note 60 | ^^^^^^^^^ 61 | 62 | If a playing note needs to be stopped, `stop_Note(note, channel = 1)` can be used. 63 | 64 | 65 | >>> fluidsynth.stop_Note(Note("C-5"), 1) 66 | True 67 | 68 | 69 | *Note* it doesn't matter if the note is actually playing; ie. nothing will break when you try to stop a note that is already stopped. 70 | 71 | Playing and Stopping NoteContainers 72 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 73 | 74 | `play_NoteContainer(notecontainer, channel = 1, velocity = 100)` and stop_NoteContainer(notecontainer, channel = 1)` work the same as `play_Note` and `stop_Note`. 75 | 76 | 77 | >>> fluidsynth.play_NoteContainer(NoteContainer(["C", "E"])) 78 | True 79 | >>> fluidsynth.stop_NoteContainer(NoteContainer(["C", "E"])) 80 | True 81 | 82 | 83 | Playing Bars, Tracks and Compositions 84 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 85 | 86 | `play_Bar`, `play_Track` and `play_Composition` all take three arguments. The first is the object itself, the second is the channel which defaults to 1, and the last one is the number of beats per minute which denotes tempo. 87 | 88 | 89 | >>> b = Bar() 90 | 91 | # Fill the Bar with NoteContainers. 92 | 93 | >>> fluidsynth.play_Bar(b, 1, 150) 94 | 95 | 96 | *Note* You can set a `bpm` attribute on a NoteContainer to change the tempo. Furthermore, you can set a Track's `instrument` attribute to a MidiInstrument object so that play_Track and play_Composition know which instrument to use. 97 | 98 | 99 | ---- 100 | 101 | 102 | Misc. MIDI Commands 103 | ------------------- 104 | 105 | Change the Instrument 106 | ^^^^^^^^^^^^^^^^^^^^^ 107 | 108 | `set_instrument(channel, instr, bank = 0)` can be used to change the instrument that is being used on a channel. You can find a list of instruments by googling for `midi instruments table`, but you can also use the `names` attribute in the MidiInstrument class found in mingus.containers.Instrument. 109 | 110 | 111 | >>> fluidsynth.set_instrument(1, 14) 112 | 113 | 114 | Panning, Modulation and Other Control Change Commands 115 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 116 | 117 | `panning(channel, value)` and `modulation(channel, value)` are shortcuts to the `control_change(channel, control, value)` function added for your convenience. There are more control change commands however. You can find tables by googling, but know that FluidSynth ignores some of the commands. 118 | 119 | 120 | ---- 121 | 122 | 123 | You can learn more about `mingus.midi.fluidsynth `_ in the reference section. 124 | 125 | * `Saving Containers as Midi File `_ 126 | * :doc:`Back to Index ` 127 | -------------------------------------------------------------------------------- /doc/wiki/tutorialGettingmingus.rst: -------------------------------------------------------------------------------- 1 | Getting mingus 2 | ============== 3 | 4 | The latest release, as well as the windows installer are available at `Python's Package Index `_, 5 | which means you can also use `easyinstall mingus` and `pip install mingus`. See also: :doc:`Setup ` 6 | 7 | You can also check out the latest source from our git repository: 8 | 9 | `git clone https://github.com/bspaans/python-mingus.git` 10 | 11 | 12 | 13 | Recommended Packages 14 | -------------------- 15 | 16 | 17 | You may also wish to install LilyPond to generate sheet music: http://www.lilypond.org/ 18 | 19 | Additionally, you can install fluidsynth for realtime MIDI playback support: http://fluidsynth.resonance.org/trac 20 | 21 | 22 | 23 | Distributions 24 | ------------- 25 | 26 | 27 | Another option is to let your platform's package manager handle the installation. mingus is available as package under the following distributions / platforms: 28 | 29 | * `Arch `_ 30 | * `Mac Ports `_ 31 | * `Ubuntu (PPA) `_ 32 | * `SuSE` 33 | 34 | 35 | Feel free to send a message to the google group if you have packaged mingus for another distribution. 36 | 37 | 38 | 39 | ---- 40 | 41 | 42 | * :doc:`Setup ` 43 | * :doc:`Back to Index ` 44 | -------------------------------------------------------------------------------- /doc/wiki/tutorialInstrumentModule.rst: -------------------------------------------------------------------------------- 1 | Tutorial 4 - Instruments 2 | ======================== 3 | 4 | We have grouped Notes in NoteContainers and NoteContainers in Bars, but before we can add Bars to Tracks, we need an Instrument class. 5 | 6 | 7 | 8 | >>> from mingus.containers.instrument import Instrument, Piano, Guitar 9 | 10 | 11 | 12 | 13 | ---- 14 | 15 | 16 | Working with Instruments 17 | ------------------------ 18 | 19 | The Instrument module is currently very basic (plans on expanding it exist), but it stores all the things the rest of mingus might need. 20 | 21 | 22 | 23 | >>> i = Instrument() 24 | >>> i.name 25 | 'Instrument' 26 | >>> i.range 27 | ('C-0', 'C-8') 28 | >>> i.clef 29 | 'bass and treble' 30 | 31 | 32 | 33 | The easiest way to use the Instrument class is probably to subclass it (see the Piano and Guiter classes), but you can also use the `set_range` function and `name` and `clef` attributes directly. 34 | 35 | 36 | 37 | >>> i = Instrument() 38 | >>> i.setrange(("C", "E")) 39 | >>> i.name = "Keyboard - five keys" 40 | >>> i.clef = "treble" 41 | 42 | 43 | 44 | 45 | ---- 46 | 47 | 48 | Range Checking 49 | -------------- 50 | 51 | Because we have set a range, we can check whether or not a note is within the range of the instrument. 52 | 53 | 54 | 55 | >>> g = Guitar() 56 | >>> p = Piano() 57 | >>> g.note_in_range("E") 58 | True 59 | >>> g.note_in_range("E-2") 60 | False 61 | >>> p.note_in_range("E-2") 62 | True 63 | 64 | 65 | 66 | To test multiple notes at once we can either use `notes_in_range` or `can_play_notes`. They both do the same thing and the alias is here for semantic reasons only. 67 | 68 | 69 | 70 | >>> g = Guitar() 71 | >>> g.can_play_notes(["A", "C", "E"]) 72 | True 73 | >>> g.can_play_notes(["A-2", "C-2", "E-2"]) 74 | False 75 | 76 | 77 | 78 | 79 | ---- 80 | 81 | 82 | Midi Instruments 83 | ---------------- 84 | 85 | Another, special subclass of Instrument is the MidiInstrument, which is used throughout the `mingus.midi` module. This instrument has an extra `midi_instr` attribute which you can set to an integer (0..127) to denote the MIDI instrument patch that should be used when playing notes. A list of instrument names is provided as `names` attribute. 86 | 87 | 88 | 89 | >>> from mingus.containers.Instrument import MidiInstrument 90 | >>> i = MidiInstrument() 91 | >>> i.midi_instr = 14 92 | 93 | 94 | 95 | 96 | 97 | ---- 98 | 99 | 100 | You can learn more about `mingus.containers.Instrument `_ in the reference section 101 | 102 | * `Tutorial 1 - The Note Class `_ 103 | * `Tutorial 2 - NoteContainers `_ 104 | * `Tutorial 3 - Bars `_ 105 | * Tutorial 4 - Instruments 106 | * `Tutorial 5 - Tracks `_ 107 | * :doc:`Back to Index ` 108 | -------------------------------------------------------------------------------- /doc/wiki/tutorialIntervals.rst: -------------------------------------------------------------------------------- 1 | Tutorial 3 - Intervals 2 | ====================== 3 | 4 | An interval in music theory describes the relationship between the pitches of two notes and is a building block for chords and scales. This module can be used to build arbitrary intervals. It also has a special recognizing function, which can determine the interval between two notes. 5 | 6 | 7 | 8 | >>> import mingus.core.intervals as intervals 9 | 10 | 11 | ---- 12 | 13 | 14 | Natural Diatonic Intervals 15 | -------------------------- 16 | 17 | Taking the natural unison, second, third, fourth, fifth, sixth or seventh of a certain note in a certain key is pretty easy with functions named just like that. The functions expect a note and a key: 18 | 19 | 20 | 21 | >>> intervals.second("C", "C") 22 | "D" 23 | >>> intervals.second("E", "C") 24 | "F" 25 | >>> intervals.second("E", "D") 26 | "F#" 27 | >>> intervals.third("C", "C") 28 | "E" 29 | >>> intervals.seventh("C", "C") 30 | "B" 31 | 32 | 33 | 34 | For people who are uncertain about what's going on here, take a look at the notes in the key of C: 35 | 36 | 37 | 38 | >>> diatonic.get_notes("C") 39 | ['C', 'D', 'E', 'F', 'G', 'A', 'B'] 40 | 41 | 42 | 43 | If we want the natural second, starting on C in the key of C, we move one step to the right and get D. If we start on the E, we get an F, etc. 44 | Now, if we want to get the third we move two steps to the right, for the fourth, three steps, etc. If we reach the end, we start back at the beginning. For instance, the natural fourth of A in the key of C is D. 45 | 46 | 47 | 48 | 49 | Absolute Intervals 50 | ------------------ 51 | 52 | The second, third, etc. functions work great and are heavily used in the chord module, but sometimes you need a specific interval starting on a note. The same function names, but prefixed with minor or major will take care of that: 53 | 54 | 55 | 56 | >>> intervals.minor_second("C") 57 | "Db" 58 | >>> intervals.major_sixth("C") 59 | "A" 60 | >>> intervals.minor_third("Cb") 61 | "Ebb" 62 | 63 | 64 | 65 | The theory behind this is a bit harder, though. If we look at the notes in the key of C again, we find that the number of half steps between C and D is two and the number of half steps between C and E is four. We know that these are respectively the second and the third natural interval. By convention we call these major. Db and Eb would be a minor second and a minor third. The same works for the other natural intervals. (See also exercise 1) 66 | 67 | *Note* `major_fifth` and `major_fourth` are better known as `perfect_fifth` and `perfect_fourth`. Both functions may be used. 68 | 69 | 70 | 71 | 72 | Interval Shorthand 73 | ------------------ 74 | 75 | The `from_shorthand` function gives you a way to handle intervals programmatically. You can use the numbers 1-7 combined with an optional accidental prefix to get the interval from a certain note. Any number of accidentals can be used, but -again- use it cautiously. No prefix means that you want the major interval, a 'b' will return the minor interval, 'bb' the diminished, '#' the augmented. 76 | 77 | 78 | 79 | >>> from_shorthand("A", "3") 80 | 'C#' 81 | >>> from_shorthand("A", "b3") 82 | 'C' 83 | 84 | 85 | 86 | The interval usually goes up, but you can let it go down as well. 87 | 88 | 89 | 90 | >>> from_shorthand("E", "2", False) 91 | 'D' 92 | 93 | 94 | 95 | Recognize Intervals 96 | ------------------- 97 | 98 | To determine what the interval between note1 and note2 is called, we can use `interval.determine(note1, note2)`. This is where we really start to notice that 'Cb' and 'B' are not the same: 99 | 100 | 101 | 102 | >>> interval.determine("C", "E"): 103 | "major third" 104 | >>> interval.determine("C", "Cb"): 105 | "minor unison" 106 | >>> interval.determine("C", "B"): 107 | "major seventh" 108 | >>> interval.determine("A", "G"): 109 | "minor seventh" 110 | >>> interval.determine("Gbb", "Ab"): 111 | "augmented second" 112 | 113 | 114 | 115 | 116 | 117 | The determine function can also output the result in shorthand, which can be fed back into `from_shorthand`. 118 | 119 | 120 | 121 | >>> interval.determine("C", "E", True) 122 | "3" 123 | >>> interval.determine("C", "Eb", True) 124 | "b3" 125 | 126 | 127 | 128 | 129 | 130 | 131 | Measuring 132 | --------- 133 | 134 | Sometimes it's just more convenient to work with integers than with shorthand. For those occasions you can use the `measure` function, which will return the number of half note steps between two notes. Also notice how the steps between C and D are different from the steps between D and C: 135 | 136 | 137 | 138 | >>> interval.measure("C", "D") 139 | 2 140 | >>> interval.measure("D", "C") 141 | 10 142 | 143 | 144 | 145 | 146 | ---- 147 | 148 | 149 | Exercises 150 | --------- 151 | 152 | * Take the minor and major thirds and fourths of the note C. Output the note and the note as integer to the screen. Do you notice something? 153 | * Create a program where a user can input a key and a note and gets the note + the natural third + the natural fifth back. This is a called a natural triad (= chord made out of three notes). 154 | 155 | 156 | ---- 157 | 158 | You can learn more about `mingus.core.intervals `_ in the reference section. 159 | 160 | * `Tutorial 1 - Working with Notes `_ 161 | * `Tutorial 2 - Keys and the Diatonic Scale `_ 162 | * Tutorial 3 - Intervals 163 | * `Tutorial 4 - Triads, Sevenths and Extended Chords `_ 164 | * :doc:`Back to Index ` 165 | -------------------------------------------------------------------------------- /doc/wiki/tutorialMidiFileOut.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 - Saving Containers as Midi Files 2 | ============================================ 3 | 4 | 5 | 6 | >>> from mingus.midi import midi_file_out 7 | 8 | 9 | 10 | 11 | ---- 12 | 13 | 14 | Saving Notes, NoteContainers, Bars, Tracks and Compositions 15 | ----------------------------------------------------------- 16 | 17 | The functions in this module all work the same and are very simple to use. `write_Note`, `write_NoteContainer`, `write_Bar`, `write_Track` and `write_Composition` all take four arguments, from which the last two are optional. The first argument specifies the filename, the second is the object itself, the third argument is the number of beats per minute (default = 120) and the last argument specifies the number of times the object should be repeated (default = 0). 18 | 19 | 20 | >>> from mingus.containers import NoteContainer 21 | >>> nc = NoteContainer(["A", "C", "E"]) 22 | >>> midi_file_out.write_NoteContainer("test.mid", nc) 23 | 24 | 25 | As in the FluidSynth module you can set the channel and velocity on Notes by setting the `channel` and `velocity` attributes. And again, to change the tempo you can set the `bpm` attribute on a NoteContainer. 26 | 27 | 28 | ---- 29 | 30 | 31 | You can learn more about `mingus.midi.MidiFileOut `_ in the reference section. 32 | 33 | * `Playing Containers with FluidSynth `_ 34 | * Saving Containers as Midi File 35 | * :doc:`Back to Index ` 36 | -------------------------------------------------------------------------------- /doc/wiki/tutorialNote.rst: -------------------------------------------------------------------------------- 1 | Tutorial 1 - Working with notes 2 | =============================== 3 | 4 | mingus was written out of a desire to have a pythonic way of working with 5 | music: simple but also correct. This module lies at the heart of the package 6 | and introduces the first building blocks: note names, accidentals and an 7 | int-to-note converter (and vice versa). 8 | 9 | 10 | To start this tutorial, open up a python shell and enter: 11 | 12 | 13 | >>> import mingus.core.notes as notes 14 | 15 | 16 | Now we are ready to work with notes. 17 | 18 | 19 | ---- 20 | 21 | 22 | Notes as Strings 23 | ---------------- 24 | 25 | A note in mingus is represented by a name (A...G) and some or no accidentals 26 | ('#' and 'b'); where 'b' lowers and '#' raises the note by one half note step. 27 | To test whether an arbitrary string is a valid note we can use 28 | `notes.is_valid_note(str)`. 29 | 30 | Some examples of valid notes: 31 | 32 | 33 | >>> notes.is_valid_note("C") 34 | True 35 | >>> notes.is_valid_note("D#") 36 | True 37 | >>> notes.is_valid_note("Eb") 38 | True 39 | >>> notes.is_valid_note("Fbb") 40 | True 41 | >>> notes.is_valid_note("G##") 42 | True 43 | 44 | 45 | Some examples of invalid notes: 46 | 47 | 48 | >>> notes.is_valid_note("c") 49 | False 50 | >>> notes.is_valid_note("D #") 51 | False 52 | >>> notes.is_valid_note("E-b") 53 | False 54 | 55 | Some, perhaps suprisingly valid notes: 56 | 57 | 58 | >>> notes.is_valid_note("C######bb") 59 | True 60 | >>> notes.is_valid_note("C#b#bb##b##bb") 61 | True 62 | 63 | 64 | As you can see, mingus can handle any number of accidentals, whether it is the 65 | sensible thing to do or not. If you want to clean up messy accidentals, you can 66 | use remove_redundant_accidentals(note). Because it's all fun and games until 67 | someone gets hurt. 68 | 69 | 70 | >>> notes.remove_redundant_accidentals("C##b") 71 | 'C#' 72 | >>> notes.remove_redundant_accidentals("C#b#bb##b##bb") 73 | 'C' 74 | 75 | 76 | 77 | ---- 78 | 79 | 80 | Notes as Integers 81 | ----------------- 82 | 83 | Sometimes it is easier to work with notes as integers in range(0,12). This is possible with the functions `notes.note_to_int(str)` and `notes.int_to_note(int)`. 84 | 85 | Note to integer 86 | ^^^^^^^^^^^^^^^ 87 | 88 | >>> notes.note_to_int("C") 89 | 0 90 | >>> notes.note_to_int("B") 91 | 11 92 | >>> notes.note_to_int("Cb") 93 | 11 94 | >>> notes.note_to_int("C#") 95 | 1 96 | >>> notes.note_to_int("Db") 97 | 1 98 | 99 | 100 | As you can see in the examples some notes return the same values. These notes are called enharmonic, because they sound the same. (There is `notes.is_enharmonic(note1, note2)` to test if two notes are enharmonic). 101 | 102 | Integer to Note 103 | ^^^^^^^^^^^^^^^ 104 | 105 | Because enharmonic notes exist, it is impossible to create a sound int-to-note converter based on an integer alone. For example; in the last piece of code we saw that B and Cb are both 11. They sound the same, but they aren't theoretically the same. This can be important when building and recognizing intervals and thus scales and chords, because intervals depend on the note name. For instance: the interval between A and B is called a major second, while the interval between A and Cb is a diminished third. `diatonic.int_to_note` does a better job at the conversion, bearing the key in mind as well. The converter in [tutorialNoteModule Note] can also handles octaves on top of that. 106 | Anyway, if you don't care about theoretically sound conversions or don't need to differentiate, this function is fine (it sounds the same, after all): 107 | 108 | 109 | 110 | >>> notes.int_to_note(0) 111 | "C" 112 | >>> notes.int_to_note(1) 113 | "C#" 114 | >>> notes.int_to_note(2) 115 | "D" 116 | >>> notes.int_to_note(3) 117 | "D#" 118 | >>> notes.int_to_note(4) 119 | "E" 120 | 121 | 122 | 123 | ---- 124 | 125 | 126 | Helper Functions 127 | ---------------- 128 | 129 | Augment and Diminish 130 | ^^^^^^^^^^^^^^^^^^^^ 131 | 132 | Augmenting and diminishing a note is a little bit harder than just slapping a '#' or 'b' on at the end of the string. For instance: when you want to augment a 'Cb' note, a 'C' would be nicer than a 'Cb#' (although, again, they are the same, but it's like using double negative). `augment` and `diminish` do a nice job at this: 133 | 134 | 135 | >>> notes.augment("C") 136 | "C#" 137 | >>> notes.augment("Cb") 138 | "C" 139 | >>> notes.augment("C#") 140 | "C##" 141 | >>> notes.augment("B") 142 | "B#" 143 | 144 | 145 | Diminishing a note: 146 | 147 | 148 | >>> notes.diminish("C") 149 | "Cb" 150 | >>> notes.diminish("C#") 151 | "C" 152 | >>> notes.diminish("Cb") 153 | "Cbb" 154 | >>> notes.diminish("B#") 155 | "B" 156 | 157 | 158 | 159 | Minor and Major conversions 160 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 161 | 162 | Minor: 163 | 164 | 165 | >>> notes.to_minor("C") 166 | "A" 167 | >>> notes.to_minor("F") 168 | "D" 169 | >>> notes.to_minor("D") 170 | "B" 171 | >>> notes.to_minor("B") 172 | "G#" 173 | 174 | 175 | Major: 176 | 177 | 178 | >>> notes.to_major("A") 179 | "C" 180 | >>> notes.to_major("D") 181 | "F" 182 | >>> notes.to_major("B") 183 | "D" 184 | >>> notes.to_major("G#") 185 | "B" 186 | 187 | 188 | ---- 189 | 190 | 191 | Exercises 192 | --------- 193 | 194 | * Write a program that asks for a note, check if it's valid and output the note which is five half notes away from it. 195 | * Get the minor equivalent of a valid note and diminish it. 196 | * Generate the first thousand fibonacci numbers and use a modulo 12 operation (eg. `n % 12`) to convert each value to a note. 197 | 198 | 199 | ---- 200 | 201 | 202 | You can learn more about `mingus.core.notes `_ in the reference section. 203 | 204 | * `Tutorial 2 - Keys and the Diatonic Scale `_ 205 | * :doc:`Back to Index ` 206 | -------------------------------------------------------------------------------- /doc/wiki/tutorialNoteContainerModule.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 - NoteContainers 2 | =========================== 3 | 4 | What if we want to store several Note objects at once (ie. intervals, chords)? We could use a simple list and be done with it, but we could 5 | also use a NoteContainer, which has some extra functionality and is used throughout this package. 6 | 7 | 8 | 9 | 10 | >>> from mingus.containers import NoteContainer 11 | 12 | 13 | 14 | 15 | ---- 16 | 17 | 18 | Creating a New NoteContainer 19 | ----------------------------- 20 | 21 | A new NoteContainer is easily created. You can create empty ones or ones already filled with notes: 22 | 23 | 24 | 25 | >>> n = NoteContainer() 26 | >>> n 27 | [] 28 | >>> n = NoteContainer(Note("A", 4)) 29 | >>> n 30 | ['A-4'] 31 | >>> n = NoteContainer("A") 32 | >>> n 33 | ['A-4'] 34 | >>> n = NoteContainer(["A-3", "C-5", "E-5"]) 35 | >>> n 36 | ['A-3', 'C-5', 'E-5'] 37 | 38 | 39 | 40 | 41 | ---- 42 | 43 | 44 | Adding Notes to a NoteContainer 45 | ------------------------------- 46 | 47 | Add a single note as a string ("C", "C-5", etc.) or a Note object. 48 | 49 | 50 | 51 | >>> n = NoteContainer() 52 | >>> n.add_note("C") 53 | >>> n 54 | ['C-4'] 55 | 56 | 57 | 58 | Add multiple notes as a list of Note object or strings; or as another NoteContainer. Single notes still work as well. The following examples all produce the same NoteContainer: 59 | 60 | 61 | 62 | >>> n = NoteContainer() 63 | >>> n.add_notes(["C", "E"]) 64 | 65 | 66 | 67 | 68 | 69 | >>> n.empty() 70 | >>> n.add_notes(NoteContainer(["C", "E"]) 71 | 72 | 73 | 74 | 75 | 76 | >>> n.empty() 77 | >>> n.add_notes([Note("C"), Note("E")]) 78 | 79 | 80 | 81 | 82 | 83 | >>> n.empty() 84 | >>> n.add_notes(Note("C")) 85 | >>> n.add_notes(Note("E")) 86 | 87 | 88 | 89 | 90 | ---- 91 | 92 | 93 | Removing Notes from a NoteContainer 94 | ----------------------------------- 95 | 96 | Remove a single note: 97 | 98 | 99 | 100 | >>> n = NoteContainer(["C", "E", "G"]) 101 | >>> n.remove_note("E") 102 | ['C-4', 'G-4'] 103 | >>> n = NoteContainer(["C-4", "C-5"]) 104 | >>> n.remove_note("C") 105 | [] 106 | 107 | 108 | 109 | Removing a single note in a single octave: 110 | 111 | 112 | 113 | >>> n = NoteContainer(["C-4", "C-5"]) 114 | >>> n.remove_note("C", 4) 115 | ['C-5'] 116 | 117 | 118 | 119 | Removing Multiple Notes from a NoteContainer 120 | -------------------------------------------- 121 | 122 | Removing more than one note from a NoteContainer: 123 | 124 | 125 | 126 | >>> n = NoteContainer(["C", "E", "G"]) 127 | >>> n.remove_notes(["C", "E"]) 128 | ['G-4'] 129 | 130 | 131 | 132 | The function `remove_notes` accepts lists of strings and Note objects, but does also accepts all the things `remove_note` accepts. 133 | 134 | 135 | ---- 136 | 137 | 138 | Using NoteContainers as Lists 139 | ----------------------------- 140 | 141 | Some basic operators and functions are overloaded which will allow you to work on NoteContainers as if they were lists. 142 | 143 | 144 | 145 | >>> n = NoteContainer(["C", "E", "G"]) 146 | >>> n[0] 147 | 'C-4' 148 | >>> n[:-1] 149 | ['C-4', 'E-4'] 150 | >>> n[0] = "D" 151 | >>> n 152 | ['D-4', 'E-4', 'G-4'] 153 | >>> len(n) 154 | 3 155 | 156 | 157 | 158 | 159 | The Overloaded '+' Operator 160 | --------------------------- 161 | 162 | The '+' operator is overloaded for NoteContainer objects. This means that you can use '+' instead of the verbose add_notes() function. 163 | 164 | 165 | 166 | >>> n = NoteContainer() 167 | >>> n + "C" 168 | ['C-4'] 169 | >>> n + ["E", "G"] 170 | ["C-4", "E-4", "G-4"] 171 | 172 | 173 | 174 | 175 | The Overloaded '-' Operator 176 | --------------------------- 177 | 178 | The '-' operator is overloaded as well and redirects calls to `remove_notes`. It can be used like this: 179 | 180 | 181 | 182 | >>> n = NoteContainer(["C", "E", "G"]) 183 | >>> n - "E" 184 | ['C-4', 'G-4'] 185 | >>> n - ["C", "G"] 186 | [] 187 | 188 | 189 | 190 | ---- 191 | 192 | 193 | Other methods 194 | ------------- 195 | 196 | The methods available in Note -transpose, augment, diminish, to_major and to_minor- are also available for NoteContainers. When one of these functions get called the NoteContainer calls the functions on every one of his Note objects. 197 | 198 | An extra function is available to `determine` the type of chord or interval in the container. 199 | 200 | 201 | 202 | >>> n = NoteContainer(["C", "E", "G"]) 203 | >>> n.determine() 204 | ['C major triad'] 205 | >>> n.determine(True) 206 | ['Cmaj'] 207 | 208 | 209 | 210 | 211 | ---- 212 | 213 | 214 | 215 | You can learn more about `mingus.containers.NoteContainers `_ in the reference section. 216 | 217 | * `Tutorial 1 - The Note Class `_ 218 | * Tutorial 2 - NoteContainers 219 | * `Tutorial 3 - Bars `_ 220 | * :doc:`Back to Index ` 221 | -------------------------------------------------------------------------------- /doc/wiki/tutorialNoteModule.rst: -------------------------------------------------------------------------------- 1 | Tutorial 1 - The Note Class 2 | =========================== 3 | 4 | `mingus.core.notes` provides a way to work with notes. However, what if we want to work with notes in different octaves? Or what if we want to set the amplitude or some effects on a note? This Note class solves those problems and also provides the cornerstone of the `mingus.containers` package. 5 | 6 | 7 | 8 | 9 | >>> from mingus.containers import Note 10 | 11 | 12 | 13 | 14 | ---- 15 | 16 | 17 | Creating and Setting Notes 18 | -------------------------- 19 | 20 | Defining and setting notes is pretty easy and can be done in a variety of ways. 21 | 22 | 23 | 24 | >>> Note("C") 25 | 'C-4' 26 | >>> Note("C", 4) 27 | 'C-4' 28 | >>> Note("C", 5) 29 | 'C-5' 30 | >>> Note("C-3") 31 | 'C-3' 32 | >>> n = Note() 33 | >>> n.set_note("C", 5) 34 | >>> n 35 | 'C-5' 36 | 37 | 38 | 39 | Note Attributes 40 | --------------- 41 | 42 | The attributes `name`, `octave` and `dynamics` are always set and accessible from the outside: 43 | 44 | 45 | 46 | >>> c = Note("C") 47 | >>> c 48 | 'C-4' 49 | >>> c.name 50 | 'C' 51 | >>> c.octave 52 | 4 53 | >>> c.dynamics 54 | {} 55 | 56 | 57 | 58 | The dynamics dictionary can be used to store additional information such as volume and effects. 59 | 60 | *NB* If you are using the mingus.midi package: setting the `velocity`, `channel` and `bpm` attribute will have an effect on the output. 61 | 62 | 63 | ---- 64 | 65 | 66 | A Better Note to Integer Converter 67 | ---------------------------------- 68 | 69 | A problem with `mingus.core.notes.note_to_int` is that it returns integers in the range 0-11. This would mean that 'Cb' and 'B' are both 11. This can be helpful, but when you are dealing with octaves you don't want this. The Note class fixes this and also overloads the int() function to make it simpler to use: 70 | 71 | 72 | 73 | >>> int(Note("C", 4)) 74 | 48 75 | >>> int(Note("Cb", 4)) 76 | 47 77 | >>> int(Note("B", 4)) 78 | 59 79 | 80 | 81 | 82 | A Better Integer to Note Converter 83 | ---------------------------------- 84 | 85 | The opposite of the previous function is `from_int(integer)`, which sets the note to the corresponding integer where 0 is a C on octave 0, 12 is a C on octave 1, etc. 86 | 87 | 88 | >>> c = Note() 89 | >>> c.from_int(12) 90 | 'C-1' 91 | 92 | 93 | 94 | 95 | ---- 96 | 97 | 98 | Methods on Notes 99 | ---------------- 100 | 101 | Octaves 102 | ^^^^^^^ 103 | 104 | Changing the octave can be done by setting the octave attribute, but the following methods can also be used: 105 | 106 | 107 | 108 | >>> a = Note("A", 5) 109 | >>> a 110 | 'A-5' 111 | >>> a.octave_up() 112 | >>> a 113 | 'A-6' 114 | >>> a.octave_down() 115 | >>> a 116 | 'A-5' 117 | >>> a.change_octave(+2) 118 | 'A-7' 119 | >>> a.change_octave(-2) 120 | 'A-5' 121 | 122 | 123 | 124 | Transposing 125 | ^^^^^^^^^^^ 126 | 127 | To move a Note an interval up or down, you can use the function `transpose(interval, up=True)`. The interval should be valid interval shorthand (see the [tutorialIntervals interval tutorial]) 128 | 129 | 130 | >>> a = Note("A") 131 | >>> a.transpose("3") 132 | >>> a 133 | 'C#-5' 134 | >>> a.transpose("4", up=False) 135 | >>> a 136 | 'G#-5' 137 | 138 | 139 | 140 | 141 | Hertz 142 | ^^^^^ 143 | 144 | Converting from and to hertz can be done using the `from_hertz(hertz, standard_pitch=440)` and `to_hertz(standard_pitch=440)` functions, where `standard_pitch` can be used to set the pitch of A-4, from which the rest is calculated. 145 | 146 | 147 | Migrated Methods 148 | ^^^^^^^^^^^^^^^^ 149 | 150 | Some of the functions in `mingus.core.notes` were added to the Note class as methods for convenience. 151 | 152 | 153 | 154 | >>> a = Note("A") 155 | >>> a 156 | 'A-4' 157 | 158 | 159 | 160 | 161 | >>> a.augment() 162 | >>> a 163 | 'A#-4' 164 | 165 | 166 | 167 | 168 | >>> a.diminish() 169 | >>> a 170 | 'A-4' 171 | 172 | 173 | 174 | >>> a.to_major() 175 | >>> a 176 | 'C-4' 177 | 178 | 179 | 180 | >>> a.to_minor() 181 | >>> a 182 | 'A-4' 183 | 184 | 185 | 186 | >>> a = Note("A#b#b") 187 | >>> a.remove_redundant_accidentals() 188 | 'A-4' 189 | 190 | 191 | 192 | ---- 193 | 194 | 195 | You can learn more about `mingus.containers.Note `_ in the reference section 196 | 197 | * Tutorial 1 - The Note Class 198 | * `Tutorial 2 - NoteContainers `_ 199 | * :doc:`Back to Index ` 200 | -------------------------------------------------------------------------------- /doc/wiki/tutorialProgressions.rst: -------------------------------------------------------------------------------- 1 | Tutorial 7 - Progressions 2 | ========================= 3 | 4 | In music theory you often deal with sequences of chords. These chord sequences are called progressions and are often written down using roman numerals. In this system the 'I' refers to the first natural triad in a key, the II to the second, etc. We can add prefixes and suffixes to denote more complex progressions like #V7, bIIdim7, etc. 5 | 6 | The progressions module provides methods which can convert progressions into chords and vice versa. It can also give suggestions for chord-substitutions. 7 | 8 | 9 | 10 | >>> import mingus.core.progressions as progressions 11 | 12 | 13 | 14 | 15 | ---- 16 | 17 | 18 | Functions to Chords 19 | ------------------- 20 | 21 | Remember the chord functions from `the chords tutorial `_? As handy as they can be, they feel a bit clunky. For example: we want to take the I, IV and V7 chord in a couple of different keys: 22 | 23 | 24 | 25 | >>> [chords.I("C"), chords.IV("C"), chords.V7("C")] 26 | >>> [chords.I("F"), chords.IV("F"), chords.V7("F")] 27 | 28 | 29 | 30 | As you can see, you would have to retype the actual progression everytime you needed it. Instead we can do this: 31 | 32 | 33 | 34 | >>> progression = ["I", "IV", "V7"] 35 | >>> progressions.to_chords(progression, "C") 36 | >>> progressions.to_chords(progression, "F") 37 | 38 | 39 | 40 | Which will do exactly the same thing and is generally a lot nicer and more modular. 41 | 42 | Another advantage is that the `to_chords` function knows about prefixes and suffixes so you denote complex progressions. You can use any number of accidentals as prefix and any known chord shorthand as suffix: 43 | 44 | 45 | 46 | >>> progressions.to_chords(["I", "bIV", "VIIdim7"]) 47 | [['C', 'E', 'G'], ['Fb', 'Ab', 'Cb'], ['B', 'D', 'F', 'Ab']] 48 | 49 | 50 | 51 | Note: since the use of '7' as suffix classicly means that you want the natural seventh chord instead of the natural triad, you have to use the 'dom7' shorthand to get the dominanth seventh - where you would use '7' when talking about chords. In other words I7 will give you a major seventh, Idom7 a dominanth seventh. 52 | 53 | 54 | ---- 55 | 56 | 57 | Chords to Functions 58 | ------------------- 59 | 60 | Now that we can convert progressions to chords, it would be nice if we could hand mingus some chords and get the progressions back. That's what `determine` is for. Here's an example that uses the chords from the previous example: 61 | 62 | 63 | 64 | >>> a = progressions.to_chords(["I", "bIV", "VIIdim7"]) 65 | >>> a 66 | [['C', 'E', 'G'], ['Fb', 'Ab', 'Cb'], ['B', 'D', 'F', 'Ab']] 67 | >>> progressions.determine(a, "C") 68 | [['tonic'], ['minor subdominant'], ['subtonic diminished seventh']] 69 | >>> progressions.determine(a, "C", True) 70 | [['I'], ['bIV'], ['viidim7']] 71 | 72 | 73 | 74 | 75 | ---- 76 | 77 | 78 | Substitutions 79 | ------------- 80 | 81 | `substitute(progression, index, depth = 0)` gives a list of possible substitutions for `progression[index]`. If depth > 0 the substitutions of each result will be recursively added as well. 82 | 83 | 84 | >>> progressions.substitute(["I", "IV", "V", "I"], 0) 85 | ["III", "VI", etc. 86 | 87 | 88 | `substitute` performs all kinds of substitutions. If you want more fine grained control you can use the functions `substitute_harmonic`, `substitute_major_for_minor`, `substitute_minor_for_major`, `substitute_diminished_for_diminished` and `substitute_diminished_for_dominant`. Check the reference section of this module to read more about them. 89 | 90 | 91 | ---- 92 | 93 | 94 | 95 | You can learn more about `mingus.core.progressions `_ in the reference section. 96 | 97 | * `Tutorial 1 - Working with Notes `_ 98 | * `Tutorial 2 - Keys and the Diatonic Scale `_ 99 | * `Tutorial 3 - Intervals `_ 100 | * `Tutorial 4 - Triads, Sevenths and Extended Chords `_ 101 | * `Tutorial 5 - Scales `_ 102 | * `Tutorial 6 - Note Value and Meter `_ 103 | * Tutorial 7 - Progressions 104 | * `Tutorial 8 - Working the Core `_ 105 | * :doc:`Back to Index ` 106 | -------------------------------------------------------------------------------- /doc/wiki/tutorialScales.rst: -------------------------------------------------------------------------------- 1 | Tutorial 5 - Scales 2 | =================== 3 | 4 | This module isn't 100% complete yet, but might already be of use to you. 5 | 6 | 7 | 8 | >>> import mingus.core.scales as scales 9 | 10 | 11 | 12 | ---- 13 | 14 | 15 | The Diatonic Scale and Its Modes 16 | -------------------------------- 17 | 18 | Throughout these tutorials we have been using a sequence of notes called the diatonic scale. You can already get it from the `diatonic` module, but it's also linked here for completeness: 19 | 20 | 21 | 22 | >>> scales.diatonic("C") 23 | ["C", "D", "E", "F", "G", "A", "B"] 24 | 25 | 26 | 27 | Sometimes we want to refer to a particular mode of the diatonic scale. This means that you start the scale on another note. The ionian mode, which is the same as the diatonic, starts on C, the dorian mode starts on D, etc. 28 | 29 | 30 | 31 | >>> scales.ionian("C") 32 | ["C", "D", "E", "F", "G", "A", "B"] 33 | >>> scales.dorian("D") 34 | ["D", "E", "F", "G", "A", "B", "C"] 35 | >>> scales.phrygian("E") 36 | ["E", "F", "G", "A", "B", "C", "D"] 37 | >>> scales.lydian("F") 38 | ["F", "G", "A", "B", "C", "D", "E"] 39 | >>> scales.mixolydian("G") 40 | ["G", "A", "B", "C", "D", "E", "F"] 41 | >>> scales.aeolian("A") 42 | ["A", "B", "C", "D", "E", "F", "G"] 43 | >>> scales.locrian("B") 44 | ["B", "C", "D", "E", "F", "G", "A"] 45 | 46 | 47 | 48 | 49 | For more on modes, see `wikipedia `_ 50 | 51 | 52 | ---- 53 | 54 | 55 | The Minor Scales 56 | ---------------- 57 | 58 | The natural minor scale is the scale starting on the minor of a key and is thus the same as the aeolian mode: 59 | 60 | 61 | 62 | >>> scales.natural_minor("A") 63 | ["A", "B", "C", "D", "E", "F", "G"] 64 | 65 | 66 | 67 | The harmonic minor differentiates from the natural minor in its raised seventh, which gives the scale a dominant seventh chord. 68 | 69 | 70 | 71 | >>> scales.harmonic_minor("A") 72 | ["A", "B", "C", "D", "E", "F", "G#"] 73 | 74 | 75 | 76 | The melodic minor also has a raised sixth to fill the gap, but 'officially' only when it's used in an ascending order. When descending, the scale to use is a minor scale. I use the word officially lightly, because this rule has been used rather inconsistently. 77 | 78 | 79 | 80 | >>> scales.melodic_minor("A") 81 | ["A", "B", "C", "D", "E", "F#", "G#"] 82 | 83 | 84 | 85 | 86 | ---- 87 | 88 | 89 | Other Scales 90 | ------------ 91 | 92 | Some other common scales are the chromatic and whole note ones. The chromatic scale basically consists of twelve notes each a minor second step apart (there are some notational differences (`source `_), but they are not supported at this point). 93 | 94 | 95 | 96 | >>> scales.chromatic("C") 97 | ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"] 98 | 99 | 100 | 101 | The whole note scale consists of six notes each a major second apart: 102 | 103 | 104 | >>> scales.whole_note("C") 105 | ["C", "D", "E", "F#", "G#", "A#"] 106 | 107 | 108 | 109 | 110 | ---- 111 | 112 | 113 | As stated before, the scales module isn't 100% finished. There has been some work done on a scale recognition function (scales.determine), but that hasn't been completed yet (see issue #17). It can do exact matches on scales that are known, but it should be able to do fuzzy matches so that it can also return possible scales over a given chord (see issue #14). 114 | 115 | 116 | ---- 117 | 118 | You can learn more about `mingus.core.scales in the reference section `_. 119 | 120 | * `Tutorial 1 - Working with Notes `_ 121 | * `Tutorial 2 - Keys and the Diatonic Scale `_ 122 | * `Tutorial 3 - Intervals `_ 123 | * `Tutorial 4 - Triads, Sevenths and Extended Chords `_ 124 | * Tutorial 5 - Scales 125 | * `Tutorial 6 - Note Value and Meter `_ 126 | * :doc:`Back to Index ` 127 | -------------------------------------------------------------------------------- /doc/wiki/tutorialSetup.rst: -------------------------------------------------------------------------------- 1 | Setup 2 | ===== 3 | 4 | Using pip 5 | ---------- 6 | 7 | 1. `pip install mingus` 8 | 9 | 10 | Installing from Source 11 | ---------------------- 12 | 13 | 1. Clone https://github.com/bspaans/python-mingus or unpack the source archive 14 | 2. `python setup.py install` 15 | 16 | 17 | 18 | Using your package manager 19 | -------------------------- 20 | 21 | mingus might be packaged for your distribution's package manager. See :doc:`getting mingus` for a list. 22 | 23 | 24 | ---- 25 | 26 | 27 | Recommended Programs 28 | -------------------- 29 | 30 | * You may also want to install LilyPond to generate sheet music: http://www.lilypond.org/ 31 | * Additionally, you can install FluidSynth for realtime MIDI playback support: http://fluidsynth.resonance.org/trac 32 | 33 | Installing FluidSynth on Windows 34 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 35 | 36 | Installing FluidSynth on Linux and Mac shouldn't be a problem, doing it on Windows is a little bit more complex: 37 | 38 | * Download and install QSynth (http://qsynth.sourceforge.net) which contains a patched version of FluidSynth which works on Windows. 39 | * Add the QSynth directory to your PATH. 40 | * In the QSynth directory, copy libfluidsynth-1.dll to libfluidsynth.dll 41 | 42 | 43 | ---- 44 | 45 | :doc:`Back to Index ` 46 | -------------------------------------------------------------------------------- /doc/wiki/tutorialSuiteModule.rst: -------------------------------------------------------------------------------- 1 | Tutorial 7 - Suite 2 | ================== 3 | 4 | The Suite class can be used to store compositions together and will probably not be used as much (if you want to write a symphony, knock yourself out though). 5 | 6 | 7 | >>> from mingus.containers import Suite 8 | 9 | 10 | 11 | 12 | ---- 13 | 14 | 15 | Creating Suites 16 | --------------- 17 | 18 | A Suite class takes no arguments to create: 19 | 20 | 21 | 22 | >>> s = Suite() 23 | 24 | 25 | 26 | Setting Attributes 27 | ------------------ 28 | 29 | The following functions will set some useful attributes. Note however that the authors and titles won't be reset on the actual compositions, only on the Suite: 30 | 31 | 32 | 33 | >>> s = Suite() 34 | >>> s.set_author('Author', 'author@email.com') 35 | >>> s.set_title('Title', 'Subtitle') 36 | 37 | 38 | 39 | 40 | 41 | 42 | ---- 43 | 44 | 45 | Adding Compositions 46 | ------------------- 47 | 48 | 49 | 50 | >>> c = Composition() 51 | >>> s = Suite() 52 | >>> s.add_composition(c) 53 | 54 | 55 | 56 | 57 | List Notation 58 | ------------- 59 | 60 | 61 | 62 | >>> c = Composition() 63 | >>> len(c) 64 | 0 65 | >>> c.add_composition(Composition()) 66 | >>> c[0] = Composition() 67 | 68 | 69 | 70 | 71 | ---- 72 | 73 | 74 | You can learn more about `mingus.containers.Suite `_ in the reference section. 75 | 76 | * `Tutorial 1 - The Note Class `_ 77 | * `Tutorial 2 - NoteContainers `_ 78 | * `Tutorial 3 - Bars `_ 79 | * `Tutorial 4 - Instruments `_ 80 | * `Tutorial 5 - Tracks `_ 81 | * `Tutorial 6 - Compositions `_ 82 | * Tutorial 7 - Suites 83 | * :doc:`Back to Index ` 84 | -------------------------------------------------------------------------------- /doc/wiki/tutorialTrackModule.rst: -------------------------------------------------------------------------------- 1 | Tutorial 5 - Tracks 2 | =================== 3 | 4 | The Track class is a simple data structure to store [tutorialBarModule Bars] in. The Class can also be used with an [tutorialInstrumentModule Instrument], but this is optional. 5 | 6 | 7 | 8 | 9 | >>> from mingus.containers import Track 10 | 11 | 12 | 13 | 14 | ---- 15 | 16 | 17 | Creating Tracks 18 | --------------- 19 | 20 | To create a new track you can simply make a new instance of `Track()`. If you want to have Instrument support, with automatic range checking, etc. you should give that as an argument: 21 | 22 | 23 | 24 | >>> t = Track() 25 | >>> t = Track(Instrument()) 26 | 27 | 28 | 29 | 30 | 31 | ---- 32 | 33 | 34 | Adding Bars 35 | ----------- 36 | 37 | Adding bars can be done using `add_bar`. 38 | 39 | 40 | 41 | >>> b = Bar() 42 | >>> t = Track() 43 | >>> t.add_bar(b) 44 | 45 | 46 | 47 | Adding Notes and NoteContainers 48 | ------------------------------- 49 | 50 | Adding notes to a track can be done using `add_notes`. This function accepts Notes, notes as strings and NoteContainers and adds them to the last Bar. If the [refMingusContainersBar Bar] is full, a new one will automatically be created. If the [refMingusContainersBar Bar] is not full but the note can't fit in, this method will return `False`. True otherwise. 51 | 52 | Also, when an Instrument is attached to the Track, but the note turns out not to be within the range of that Instrument, an !InstrumentRangeError will be raised. 53 | 54 | 55 | 56 | >>> t = Track() 57 | >>> t.add_notes("C") 58 | True 59 | 60 | 61 | 62 | The Overloaded '+' Operator 63 | --------------------------- 64 | 65 | This should be familiar stuff by now, but the '+' operator is overloaded for the Track class as well and accepts strings, NoteContainers, Notes and Bars. 66 | 67 | 68 | 69 | >>> t = Track() 70 | >>> b = Bar() 71 | >>> t + b 72 | >>> t + "C-4" 73 | True 74 | 75 | 76 | 77 | 78 | ---- 79 | 80 | 81 | List Notation 82 | ------------- 83 | 84 | Tracks, like Bars and NoteContainers can be used as lists as well. 85 | 86 | 87 | >>> t = Track() 88 | >>> b = Bar() 89 | >>> b + "C" 90 | True 91 | >>> t + b 92 | True 93 | >>> t[0] 94 | [[0.0, 4, ["C-4"]]] 95 | >>> t[0] = Bar() 96 | >>> t[0] 97 | [[]] 98 | 99 | 100 | 101 | 102 | ---- 103 | 104 | 105 | Other Methods 106 | ------------- 107 | 108 | The usual methods: -transpose, augment, diminish, to_major and to_minor- are also available on Tracks. Calls to these functions will get redirected to each Bar's equivalent. 109 | 110 | 111 | ---- 112 | 113 | 114 | 115 | You can learn more about `mingus.containers.Track in the reference section `_ 116 | 117 | * `Tutorial 1 - The Note Class `_ 118 | * `Tutorial 2 - NoteContainers `_ 119 | * `Tutorial 3 - Bars `_ 120 | * `Tutorial 4 - Instruments `_ 121 | * Tutorial 5 - Tracks 122 | * `Tutorial 6 - Compositions `_ 123 | * :doc:`Back to Index ` 124 | -------------------------------------------------------------------------------- /mingus/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Music theory Python package 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | """See README.""" 20 | -------------------------------------------------------------------------------- /mingus/containers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import 3 | 4 | # mingus - Music theory Python package, containers package. 5 | # Copyright (C) 2008-2009, Bart Spaans 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | from mingus.containers.note import Note 21 | from mingus.containers.note_container import NoteContainer 22 | from mingus.containers.bar import Bar 23 | from mingus.containers.track import Track 24 | from mingus.containers.composition import Composition 25 | from mingus.containers.suite import Suite 26 | from mingus.containers.instrument import Instrument, Piano, Guitar, MidiInstrument 27 | -------------------------------------------------------------------------------- /mingus/containers/composition.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import absolute_import 4 | 5 | # mingus - Music theory Python package, composition module. 6 | # Copyright (C) 2008-2009, Bart Spaans 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | from mingus.containers.mt_exceptions import UnexpectedObjectError 22 | 23 | 24 | class Composition(object): 25 | 26 | """A composition object. 27 | 28 | The Composition class is a datastructure for working with Tracks. 29 | 30 | Composition can be stored together in Suites. 31 | """ 32 | 33 | title = "Untitled" 34 | subtitle = "" 35 | author = "" 36 | email = "" 37 | description = "" 38 | tracks = [] 39 | selected_tracks = [] 40 | 41 | def __init__(self): 42 | self.empty() 43 | 44 | def empty(self): 45 | """Remove all the tracks from this class.""" 46 | self.tracks = [] 47 | 48 | def reset(self): 49 | """Reset the information in this class. 50 | 51 | Remove the track and composer information. 52 | """ 53 | self.empty() 54 | self.set_title() 55 | self.set_author() 56 | 57 | def add_track(self, track): 58 | """Add a track to the composition. 59 | 60 | Raise an UnexpectedObjectError if the argument is not a 61 | mingus.containers.Track object. 62 | """ 63 | if not hasattr(track, "bars"): 64 | raise UnexpectedObjectError( 65 | "Unexpected object '%s', " 66 | "expecting a mingus.containers.Track object" % track 67 | ) 68 | self.tracks.append(track) 69 | self.selected_tracks = [len(self.tracks) - 1] 70 | 71 | def add_note(self, note): 72 | """Add a note to the selected tracks. 73 | 74 | Everything container.Track supports in __add__ is accepted. 75 | """ 76 | for n in self.selected_tracks: 77 | self.tracks[n] + note 78 | 79 | def set_title(self, title="Untitled", subtitle=""): 80 | """Set the title and subtitle of the piece.""" 81 | self.title = title 82 | self.subtitle = subtitle 83 | 84 | def set_author(self, author="", email=""): 85 | """Set the title and author of the piece.""" 86 | self.author = author 87 | self.email = email 88 | 89 | def __add__(self, value): 90 | """Enable the '+' operator for Compositions. 91 | 92 | Notes, note strings, NoteContainers, Bars and Tracks are accepted. 93 | """ 94 | if hasattr(value, "bars"): 95 | return self.add_track(value) 96 | else: 97 | return self.add_note(value) 98 | 99 | def __getitem__(self, index): 100 | """Enable the '[]' notation.""" 101 | return self.tracks[index] 102 | 103 | def __setitem__(self, index, value): 104 | """Enable the '[] =' notation.""" 105 | self.tracks[index] = value 106 | 107 | def __len__(self): 108 | """Enable the len() function.""" 109 | return len(self.tracks) 110 | 111 | def __repr__(self): 112 | """Return a string representing the class.""" 113 | result = "" 114 | for x in self.tracks: 115 | result += str(x) 116 | return result 117 | -------------------------------------------------------------------------------- /mingus/containers/mt_exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Music theory Python package, mt_exceptions module. 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | 20 | class NoteFormatError(Exception): 21 | 22 | pass 23 | 24 | 25 | class UnexpectedObjectError(Exception): 26 | 27 | pass 28 | 29 | 30 | class MeterFormatError(Exception): 31 | 32 | pass 33 | 34 | 35 | class InstrumentRangeError(Exception): 36 | 37 | pass 38 | -------------------------------------------------------------------------------- /mingus/containers/suite.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import absolute_import 4 | 5 | # mingus - Music theory Python package, suite module. 6 | # Copyright (C) 2008-2009, Bart Spaans 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | from mingus.containers.mt_exceptions import UnexpectedObjectError 22 | 23 | 24 | class Suite(object): 25 | 26 | """A suite object. 27 | 28 | The Suite class is a datastructure that stores Composition objects. 29 | """ 30 | 31 | title = "Untitled" 32 | subtitle = "" 33 | author = "" 34 | email = "" 35 | description = "" 36 | compositions = [] 37 | 38 | def __init__(self): 39 | pass 40 | 41 | def add_composition(self, composition): 42 | """Add a composition to the suite. 43 | 44 | Raise an UnexpectedObjectError when the supplied argument is not a 45 | Composition object. 46 | """ 47 | if not hasattr(composition, "tracks"): 48 | raise UnexpectedObjectError( 49 | "Object '%s' not expected. Expecting " 50 | "a mingus.containers.Composition object." % composition 51 | ) 52 | self.compositions.append(composition) 53 | return self 54 | 55 | def set_author(self, author, email=""): 56 | """Set the author of the suite.""" 57 | self.author = author 58 | self.email = email 59 | 60 | def set_title(self, title, subtitle=""): 61 | """Set the title and the subtitle of the suite.""" 62 | self.title = title 63 | self.subtitle = subtitle 64 | 65 | def __len__(self): 66 | """Enable the len() function.""" 67 | return len(self.compositions) 68 | 69 | def __getitem__(self, index): 70 | """Enable the '[]' notation.""" 71 | return self.compositions[index] 72 | 73 | def __setitem__(self, index, value): 74 | """Enable the '[] =' notation.""" 75 | if not hasattr(value, "tracks"): 76 | raise UnexpectedObjectError( 77 | "Object '%s' is not expected. " 78 | "Expecting a " 79 | "mingus.containers.Composition object." % value 80 | ) 81 | self.compositions[index] = value 82 | 83 | def __add__(self, composition): 84 | """Enable the '+' operator for Compositions.""" 85 | return self.add_composition(composition) 86 | -------------------------------------------------------------------------------- /mingus/core/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Mingus - Music theory Python module, core package. 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | __all__ = [ 20 | "notes", 21 | "keys", 22 | "intervals", 23 | "chords", 24 | "scales", 25 | "meter", 26 | "progressions", 27 | "mt_exceptions", 28 | "value", 29 | ] 30 | -------------------------------------------------------------------------------- /mingus/core/meter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Music theory Python package, meter module. 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | """Module for dealing with meters. 20 | 21 | A meter is represented by a tuple. 4/4 time would look like (4,4), 3/4 like 22 | (3,4), etc. 23 | """ 24 | from __future__ import absolute_import 25 | 26 | common_time = (4, 4) 27 | cut_time = (2, 2) 28 | 29 | 30 | def valid_beat_duration(duration): 31 | """Return True when log2(duration) is an integer.""" 32 | if duration == 0: 33 | return False 34 | elif duration == 1: 35 | return True 36 | else: 37 | r = duration 38 | while r != 1: 39 | if r % 2 == 1: 40 | return False 41 | r /= 2 42 | return True 43 | 44 | 45 | def is_valid(meter): 46 | """Return True if meter is a valid tuple representation of a meter. 47 | 48 | Examples for meters are (3,4) for 3/4, (4,4) for 4/4, etc. 49 | """ 50 | return meter[0] > 0 and valid_beat_duration(meter[1]) 51 | 52 | 53 | def is_compound(meter): 54 | """Return True if meter is a compound meter, False otherwise. 55 | 56 | Examples: 57 | >>> is_compound((3,4)) 58 | True 59 | >>> is_compound((4,4)) 60 | False 61 | """ 62 | return is_valid(meter) and meter[0] % 3 == 0 and 6 <= meter[0] 63 | 64 | 65 | def is_simple(meter): 66 | """Return True if meter is a simple meter, False otherwise. 67 | 68 | Examples: 69 | >>> is_simple((3,4)) 70 | True 71 | >>> is_simple((4,4)) 72 | True 73 | """ 74 | return is_valid(meter) 75 | 76 | 77 | def is_asymmetrical(meter): 78 | """Return True if meter is an asymmetrical meter, False otherwise. 79 | 80 | Examples: 81 | >>> is_asymmetrical((3,4)) 82 | True 83 | >>> is_asymmetrical((4,4)) 84 | False 85 | """ 86 | return is_valid(meter) and meter[0] % 2 == 1 87 | -------------------------------------------------------------------------------- /mingus/core/mt_exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Music theory Python package, mt_exceptions module. 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | 20 | class Error(Exception): 21 | 22 | pass 23 | 24 | 25 | class FormatError(Error): 26 | 27 | pass 28 | 29 | 30 | class NoteFormatError(Error): 31 | 32 | pass 33 | 34 | 35 | class KeyError(Error): 36 | 37 | pass 38 | 39 | 40 | class RangeError(Error): 41 | 42 | pass 43 | 44 | 45 | class FingerError(Error): 46 | 47 | pass 48 | -------------------------------------------------------------------------------- /mingus/core/notes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Music theory Python package, notes module. 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # Copyright (C) 2011, Carlo Stemberger 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | """Basic module for notes. 21 | 22 | This module is the foundation of the music theory package. 23 | 24 | It handles conversions from integers to notes and vice versa and thus 25 | enables simple calculations. 26 | """ 27 | from __future__ import absolute_import 28 | 29 | from mingus.core.mt_exceptions import NoteFormatError, RangeError, FormatError 30 | from six.moves import range 31 | 32 | _note_dict = {"C": 0, "D": 2, "E": 4, "F": 5, "G": 7, "A": 9, "B": 11} 33 | fifths = ["F", "C", "G", "D", "A", "E", "B"] 34 | 35 | 36 | def int_to_note(note_int, accidentals="#"): 37 | """Convert integers in the range of 0-11 to notes in the form of C or C# 38 | or Db. 39 | 40 | Throw a RangeError exception if the note_int is not in the range 0-11. 41 | 42 | If not specified, sharps will be used. 43 | 44 | Examples: 45 | >>> int_to_note(0) 46 | 'C' 47 | >>> int_to_note(3) 48 | 'D#' 49 | >>> int_to_note(3, 'b') 50 | 'Eb' 51 | """ 52 | if note_int not in range(12): 53 | raise RangeError("int out of bounds (0-11): %d" % note_int) 54 | ns = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] 55 | nf = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"] 56 | if accidentals == "#": 57 | return ns[note_int] 58 | elif accidentals == "b": 59 | return nf[note_int] 60 | else: 61 | raise FormatError("'%s' not valid as accidental" % accidentals) 62 | 63 | 64 | def is_enharmonic(note1, note2): 65 | """Test whether note1 and note2 are enharmonic, i.e. they sound the same.""" 66 | return note_to_int(note1) == note_to_int(note2) 67 | 68 | 69 | def is_valid_note(note): 70 | """Return True if note is in a recognised format. False if not.""" 71 | if note[0] not in _note_dict: 72 | return False 73 | for post in note[1:]: 74 | if post != "b" and post != "#": 75 | return False 76 | return True 77 | 78 | 79 | def note_to_int(note): 80 | """Convert notes in the form of C, C#, Cb, C##, etc. to an integer in the 81 | range of 0-11. 82 | 83 | Throw a NoteFormatError exception if the note format is not recognised. 84 | """ 85 | if is_valid_note(note): 86 | val = _note_dict[note[0]] 87 | else: 88 | raise NoteFormatError("Unknown note format '%s'" % note) 89 | 90 | # Check for '#' and 'b' postfixes 91 | for post in note[1:]: 92 | if post == "b": 93 | val -= 1 94 | elif post == "#": 95 | val += 1 96 | return val % 12 97 | 98 | 99 | def reduce_accidentals(note): 100 | """Reduce any extra accidentals to proper notes. 101 | 102 | Example: 103 | >>> reduce_accidentals('C####') 104 | 'E' 105 | """ 106 | val = note_to_int(note[0]) 107 | for token in note[1:]: 108 | if token == "b": 109 | val -= 1 110 | elif token == "#": 111 | val += 1 112 | else: 113 | raise NoteFormatError("Unknown note format '%s'" % note) 114 | if val >= note_to_int(note[0]): 115 | return int_to_note(val % 12) 116 | else: 117 | return int_to_note(val % 12, "b") 118 | 119 | 120 | def remove_redundant_accidentals(note): 121 | """Remove redundant sharps and flats from the given note. 122 | 123 | Examples: 124 | >>> remove_redundant_accidentals('C##b') 125 | 'C#' 126 | >>> remove_redundant_accidentals('Eb##b') 127 | 'E' 128 | """ 129 | val = 0 130 | for token in note[1:]: 131 | if token == "b": 132 | val -= 1 133 | elif token == "#": 134 | val += 1 135 | result = note[0] 136 | while val > 0: 137 | result = augment(result) 138 | val -= 1 139 | while val < 0: 140 | result = diminish(result) 141 | val += 1 142 | return result 143 | 144 | 145 | def augment(note): 146 | """Augment a given note. 147 | 148 | Examples: 149 | >>> augment('C') 150 | 'C#' 151 | >>> augment('Cb') 152 | 'C' 153 | """ 154 | if note[-1] != "b": 155 | return note + "#" 156 | else: 157 | return note[:-1] 158 | 159 | 160 | def diminish(note): 161 | """Diminish a given note. 162 | 163 | Examples: 164 | >>> diminish('C') 165 | 'Cb' 166 | >>> diminish('C#') 167 | 'C' 168 | """ 169 | if note[-1] != "#": 170 | return note + "b" 171 | else: 172 | return note[:-1] 173 | -------------------------------------------------------------------------------- /mingus/extra/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import absolute_import 4 | 5 | # mingus - Music theory Python package, extra package. 6 | # Copyright (C) 2008-2009, Bart Spaans 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | from mingus.extra import lilypond 22 | from mingus.extra.tunings import StringTuning 23 | 24 | __all__ = ["lilypond", "fft", "musicxml", "tunings", "tablature", "StringTuning"] 25 | -------------------------------------------------------------------------------- /mingus/midi/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import absolute_import 4 | 5 | # mingus - Music theory Python package, midi package. 6 | # Copyright (C) 2008-2009, Bart Spaans 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | from mingus.midi.sequencer import Sequencer 22 | from mingus.midi.sequencer_observer import SequencerObserver 23 | 24 | __all__ = [ 25 | "Sequencer", 26 | "SequencerObserver", 27 | "midi_file_in", 28 | "midi_file_out", 29 | "midi_track", 30 | "fluidsynth", 31 | ] 32 | -------------------------------------------------------------------------------- /mingus/midi/midi_events.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Headers 4 | FILE_HEADER = b"MThd" 5 | TRACK_HEADER = b"MTrk" 6 | 7 | # MIDI Channel Events 8 | NOTE_OFF = 0x08 9 | NOTE_ON = 0x09 10 | NOTE_AFTERTOUCH = 0x0A 11 | CONTROLLER = 0x0B 12 | PROGRAM_CHANGE = 0x0C 13 | CHANNEL_AFTERTOUCH = 0x0D 14 | PITCH_BEND = 0x0E 15 | META_EVENT = b"\xff" 16 | 17 | # MIDI Controller Type 18 | BANK_SELECT = 0x00 19 | MODULATION = 0x01 20 | BREATH_CONTROLLER = 0x02 21 | FOOT_CONTROLLER = 0x04 22 | PORTAMENTO_TIME = 0x05 23 | DATA_ENTRY_MSB = 0x06 24 | MAIN_VOLUME = 0x07 25 | BALANCE = 0x08 26 | PAN = 0x0A 27 | EXPRESSION_CONTROLLER = 0x0B 28 | EFFECT_CONTROL_1 = 0x0C 29 | EFFECT_CONTROL_2 = 0x0D 30 | 31 | # Meta Events 32 | SEQUENCE_NUMBER = b"\x00" 33 | TEXT_EVENT = b"\x01" 34 | COPYRIGHT_NOTICE = b"\x02" 35 | TRACK_NAME = b"\x03" 36 | INSTRUMENT_NAME = b"\x04" 37 | LYRICS = b"\x05" 38 | MARKER = b"\x06" 39 | CUE_POINT = b"\x07" 40 | MIDI_CHANNEL_PREFIX = b"\x20" 41 | END_OF_TRACK = b"\x2F" 42 | SET_TEMPO = b"\x51" 43 | SMPTE_OFFSET = b"\x54" 44 | TIME_SIGNATURE = b"\x58" 45 | KEY_SIGNATURE = b"\x59" 46 | -------------------------------------------------------------------------------- /mingus/midi/sequencer_observer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # mingus - Music theory Python package, sequencer_observer module. 4 | # Copyright (C) 2008-2009, Bart Spaans 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | """Provides an easy to extend base class that can be used to observe a 20 | Sequencer. 21 | 22 | Each time a Sequencer starts playing a new Note, Bar, w/e, an event is 23 | fired; this SequencerObserver intercepts the event messages and calls the 24 | proper function so you only have to implement the functions for the events 25 | you need to see. 26 | """ 27 | from __future__ import absolute_import 28 | 29 | from mingus.midi.sequencer import Sequencer 30 | 31 | 32 | class SequencerObserver(object): 33 | 34 | """An easy to extend base class that can be used to observe a Sequencer. 35 | 36 | Each time a Sequencer starts playing a new Note, Bar, w/e, an event is 37 | fired; this SequencerObserver intercepts the event messages and calls 38 | the proper function so you only have to implement the functions for the 39 | events you need to see. 40 | """ 41 | 42 | # Low Level MIDI Events 43 | def play_int_note_event(self, int_note, channel, velocity): 44 | pass 45 | 46 | def stop_int_note_event(self, int_note, channel): 47 | pass 48 | 49 | def cc_event(self, channel, control, value): 50 | pass 51 | 52 | def instr_event(self, channel, instr, bank): 53 | pass 54 | 55 | def sleep(self, seconds): 56 | pass 57 | 58 | def play_Note(self, note, channel, velocity): 59 | pass 60 | 61 | def stop_Note(self, note, channel): 62 | pass 63 | 64 | def play_NoteContainer(self, notes, channel): 65 | pass 66 | 67 | def stop_NoteContainer(self, notes, channel): 68 | pass 69 | 70 | def play_Bar(self, bar, channel, bpm): 71 | pass 72 | 73 | def play_Bars(self, bars, channels, bpm): 74 | pass 75 | 76 | def play_Track(self, track, channel, bpm): 77 | pass 78 | 79 | def play_Tracks(self, tracks, channels, bpm): 80 | pass 81 | 82 | def play_Composition(self, composition, channels, bpm): 83 | pass 84 | 85 | def notify(self, msg_type, params): 86 | if msg_type == Sequencer.MSG_PLAY_INT: 87 | self.play_int_note_event( 88 | params["note"], params["channel"], params["velocity"] 89 | ) 90 | elif msg_type == Sequencer.MSG_STOP_INT: 91 | self.stop_int_note_event(params["note"], params["channel"]) 92 | elif msg_type == Sequencer.MSG_CC: 93 | self.cc_event(params["channel"], params["control"], params["value"]) 94 | elif msg_type == Sequencer.MSG_INSTR: 95 | self.instr_event(params["channel"], params["instr"], params["bank"]) 96 | elif msg_type == Sequencer.MSG_SLEEP: 97 | self.sleep(params["s"]) 98 | elif msg_type == Sequencer.MSG_PLAY_NOTE: 99 | self.play_Note(params["note"], params["channel"], params["velocity"]) 100 | elif msg_type == Sequencer.MSG_STOP_NOTE: 101 | self.stop_Note(params["note"], params["channel"]) 102 | elif msg_type == Sequencer.MSG_PLAY_NC: 103 | self.play_NoteContainer(params["notes"], params["channel"]) 104 | elif msg_type == Sequencer.MSG_STOP_NC: 105 | self.stop_NoteContainer(params["notes"], params["channel"]) 106 | elif msg_type == Sequencer.MSG_PLAY_BAR: 107 | self.play_Bar(params["bar"], params["channel"], params["bpm"]) 108 | elif msg_type == Sequencer.MSG_PLAY_BARS: 109 | self.play_Bars(params["bars"], params["channels"], params["bpm"]) 110 | elif msg_type == Sequencer.MSG_PLAY_TRACK: 111 | self.play_Track(params["track"], params["channel"], params["bpm"]) 112 | elif msg_type == Sequencer.MSG_PLAY_TRACKS: 113 | self.play_Tracks(params["tracks"], params["channels"], params["bpm"]) 114 | elif msg_type == Sequencer.MSG_PLAY_COMPOSITION: 115 | self.play_Composition( 116 | params["composition"], params["channels"], params["bpm"] 117 | ) 118 | -------------------------------------------------------------------------------- /mingus/midi/win32midi.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import sys 4 | 5 | # Real-time MIDI playback in Win32 6 | # No extra dlls or modules needed, uses built-in ctypes module. 7 | # By Ben Fisher, 2009, GPLv3 8 | # referencing code: 9 | # http://www.sabren.net/rants/2000/01/20000129a.php3 (uses out-of-date libraries) 10 | # http://msdn.microsoft.com/en-us/library/ms711632.aspx 11 | # Note: will raise Win32MidiException if no midi device is found, and under other cases! 12 | # Must call .openDevice() before use! 13 | # Remember to call .closeDevice() when done. 14 | 15 | if sys.platform != "win32": 16 | raise RuntimeError("Intended for use on win32 platform") 17 | import time 18 | from ctypes import windll, c_void_p, c_int, byref 19 | 20 | 21 | class Win32MidiException(Exception): 22 | pass 23 | 24 | 25 | class Win32MidiPlayer(object): 26 | def __init__(self): 27 | self.midiOutOpenErrorCodes = { 28 | ( 29 | 64 + 4 30 | ): "MIDIERR_NODEVICE No MIDI port was found. This error occurs only when the mapper is opened.", 31 | (0 + 4): "MMSYSERR_ALLOCATED The specified resource is already allocated.", 32 | ( 33 | 0 + 2 34 | ): "MMSYSERR_BADDEVICEID The specified device identifier is out of range.", 35 | ( 36 | 0 + 11 37 | ): "MMSYSERR_INVALPARAM The specified pointer or structure is invalid.", 38 | (0 + 7): "MMSYSERR_NOMEM The system is unable to allocate or lock memory.", 39 | } 40 | self.midiOutShortErrorCodes = { 41 | ( 42 | 64 + 6 43 | ): "MIDIERR_BADOPENMODE The application sent a message without a status byte to a stream handle.", 44 | (64 + 3): "MIDIERR_NOTREADY The hardware is busy with other data.", 45 | (0 + 5): "MMSYSERR_INVALHANDLE The specified device handle is invalid.", 46 | } 47 | self.winmm = windll.winmm 48 | 49 | def countDevices(self): 50 | return self.winmm.midiOutGetNumDevs() 51 | 52 | def openDevice( 53 | self, deviceNumber=-1 54 | ): # device -1 refers to the default set in midi mapper, usually a good choice 55 | # it took me some experimentation to get this to work... 56 | self.hmidi = c_void_p() 57 | rc = self.winmm.midiOutOpen(byref(self.hmidi), deviceNumber, 0, 0, 0) 58 | if rc != 0: 59 | raise Win32MidiException( 60 | "Error opening device, " 61 | + self.midiOutOpenErrorCodes.get(rc, "Unknown error.") 62 | ) 63 | 64 | def closeDevice(self): 65 | rc = self.winmm.midiOutClose(self.hmidi) 66 | if rc != 0: 67 | raise Win32MidiException("Error closing device") 68 | 69 | def sendNote( 70 | self, pitch, duration=1.0, channel=1, volume=60 71 | ): # duration in seconds 72 | midimsg = 0x90 + ((pitch) * 0x100) + (volume * 0x10000) + channel 73 | mm = c_int(midimsg) 74 | rc = self.winmm.midiOutShortMsg(self.hmidi, mm) 75 | if rc != 0: 76 | raise Win32MidiException( 77 | "Error opening device, " 78 | + self.midiOutShortErrorCodes.get(rc, "Unknown error.") 79 | ) 80 | 81 | time.sleep(duration) 82 | 83 | # turn it off 84 | midimsg = 0x80 + ((pitch) * 0x100) + channel 85 | mm = c_int(midimsg) 86 | rc = self.winmm.midiOutShortMsg(self.hmidi, mm) 87 | if rc != 0: 88 | raise Win32MidiException( 89 | "Error sending event, " 90 | + self.midiOutShortErrorCodes.get(rc, "Unknown error.") 91 | ) 92 | 93 | def rawNoteOn(self, pitch, channel=1, v=60): 94 | midimsg = 0x90 + ((pitch) * 0x100) + (v * 0x10000) + channel 95 | mm = c_int(midimsg) 96 | rc = self.winmm.midiOutShortMsg(self.hmidi, mm) 97 | if rc != 0: 98 | raise Win32MidiException( 99 | "Error sending event, " 100 | + self.midiOutShortErrorCodes.get(rc, "Unknown error.") 101 | ) 102 | 103 | def rawNoteOff(self, pitch, channel=1): 104 | midimsg = 0x80 + ((pitch) * 0x100) + channel 105 | mm = c_int(midimsg) 106 | rc = self.winmm.midiOutShortMsg(self.hmidi, mm) 107 | if rc != 0: 108 | raise Win32MidiException( 109 | "Error sending event, " 110 | + self.midiOutShortErrorCodes.get(rc, "Unknown error.") 111 | ) 112 | 113 | def programChange(self, program, channel=1): 114 | p = program 115 | v = 0 116 | midimsg = 0xC0 + ((p) * 0x100) + (v * 0x10000) + channel 117 | mm = c_int(midimsg) 118 | rc = self.winmm.midiOutShortMsg(self.hmidi, mm) 119 | if rc != 0: 120 | raise Win32MidiException( 121 | "Error sending event, " 122 | + self.midiOutShortErrorCodes.get(rc, "Unknown error.") 123 | ) 124 | 125 | def controllerChange(self, controller, val, channel=1): 126 | midimsg = 0xB0 + ((controller) * 0x100) + (val * 0x10000) + channel 127 | mm = c_int(midimsg) 128 | rc = self.winmm.midiOutShortMsg(self.hmidi, mm) 129 | if rc != 0: 130 | raise Win32MidiException( 131 | "Error sending event, " 132 | + self.midiOutShortErrorCodes.get(rc, "Unknown error.") 133 | ) 134 | -------------------------------------------------------------------------------- /mingus/midi/win32midisequencer.py: -------------------------------------------------------------------------------- 1 | # mingus - Music theory Python package, win32midisequencer module. 2 | # Copyright (C) 2008-2010, Bart Spaans, Ben Fisher 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | """MIDI playback support for mingus in MS Windows. 18 | 19 | This module will use the default MIDI output device, which can be chosen in 20 | the control panel. No extra dlls or modules are needed; uses built-in ctypes 21 | module. 22 | 23 | Caution: this will throw Win32MidiException if there is no device, or device 24 | can't be opened. 25 | """ 26 | from __future__ import absolute_import 27 | 28 | import sys 29 | 30 | # We should be able to import this module on non-win32 systems without 31 | # raising exceptions. So instead, raise in the init() method. 32 | if sys.platform == "win32": 33 | from mingus.midi import win32midi 34 | 35 | from mingus.midi.sequencer import Sequencer 36 | 37 | 38 | class Win32MidiSequencer(Sequencer): 39 | output = None 40 | midplayer = None 41 | 42 | def init(self): 43 | if sys.platform != "win32": 44 | raise RuntimeError("Intended for use on win32 platform") 45 | self.midplayer = win32midi.Win32MidiPlayer() 46 | self.midplayer.openDevice() 47 | 48 | def __del__(self): 49 | self.midplayer.closeDevice() 50 | 51 | # Implement Sequencer's interface 52 | 53 | def play_event(self, note, channel, velocity): 54 | self.midplayer.rawNoteOn(note, channel, velocity) 55 | 56 | def stop_event(self, note, channel): 57 | self.midplayer.rawNoteOff(note, channel) 58 | 59 | def cc_event(self, channel, control, value): 60 | self.midplayer.controllerChange(control, value, channel) 61 | 62 | def instr_event(self, channel, instr, bank): 63 | # "bank" currently not supported 64 | self.midplayer.programChange(instr, channel) 65 | -------------------------------------------------------------------------------- /mingus_examples/play_progression/play-progression.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | *** Description *** 5 | 6 | Converts a progression to chords and plays them using fluidsynth. 7 | 8 | You should specify the SF2 soundfont file. 9 | """ 10 | 11 | from mingus.core import progressions, intervals 12 | from mingus.core import chords as ch 13 | from mingus.containers import NoteContainer, Note 14 | from mingus.midi import fluidsynth 15 | import time 16 | import sys 17 | from random import random 18 | 19 | SF2 = "soundfont_example.sf2" 20 | progression = [ 21 | "I", 22 | "vi", 23 | "ii", 24 | "iii7", 25 | "I7", 26 | "viidom7", 27 | "iii7", 28 | "V7", 29 | ] 30 | key = "C" 31 | chords = progressions.to_chords(progression, key) 32 | if not fluidsynth.init(SF2): 33 | print("Couldn't load soundfont", SF2) 34 | sys.exit(1) 35 | while 1: 36 | i = 0 37 | for chord in chords: 38 | c = NoteContainer(chords[i]) 39 | l = Note(c[0].name) 40 | p = c[1] 41 | l.octave_down() 42 | print(ch.determine(chords[i])[0]) 43 | 44 | # Play chord and lowered first note 45 | 46 | fluidsynth.play_NoteContainer(c) 47 | fluidsynth.play_Note(l) 48 | time.sleep(1.0) 49 | 50 | # Play highest note in chord 51 | 52 | fluidsynth.play_Note(c[-1]) 53 | 54 | # 50% chance on a bass note 55 | 56 | if random() > 0.50: 57 | p = Note(c[1].name) 58 | p.octave_down() 59 | fluidsynth.play_Note(p) 60 | time.sleep(0.50) 61 | 62 | # 50% chance on a ninth 63 | 64 | if random() > 0.50: 65 | l = Note(intervals.second(c[0].name, key)) 66 | l.octave_up() 67 | fluidsynth.play_Note(l) 68 | time.sleep(0.25) 69 | 70 | # 50% chance on the second highest note 71 | 72 | if random() > 0.50: 73 | fluidsynth.play_Note(c[-2]) 74 | time.sleep(0.25) 75 | fluidsynth.stop_NoteContainer(c) 76 | fluidsynth.stop_Note(l) 77 | fluidsynth.stop_Note(p) 78 | i += 1 79 | print("-" * 20) 80 | -------------------------------------------------------------------------------- /mingus_examples/pygame-drum/pad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/mingus_examples/pygame-drum/pad.png -------------------------------------------------------------------------------- /mingus_examples/pygame-piano/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/mingus_examples/pygame-piano/keys.png -------------------------------------------------------------------------------- /requirements-dev.in: -------------------------------------------------------------------------------- 1 | black 2 | twine 3 | wheel 4 | -------------------------------------------------------------------------------- /scripts/build_api_docs.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # mingus 0.5 4 | 5 | 6 | echo mingus 0.5 - Generate documentation and upload to googlecode 7 | echo 8 | echo 9 | echo =========================Generating documentation========================= 10 | echo 11 | 12 | mkdir tmpwiki && ./api_doc_generator.py tmpwiki && 13 | mv tmpwiki/*.rst ../doc/wiki/ && rm -r tmpwiki && 14 | 15 | echo 16 | echo Done 17 | -------------------------------------------------------------------------------- /scripts/build_github_pages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) 4 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 5 | 6 | cd "$DIR/../" 7 | git checkout sphinx-workspace 8 | ./build.sh 9 | 10 | git checkout gh-pages 11 | ./build.sh 12 | 13 | git checkout "$CURRENT_BRANCH" 14 | 15 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | from setuptools import setup 3 | except ImportError: 4 | from distutils.core import setup 5 | 6 | 7 | setup( 8 | name="mingus", 9 | version="0.6.0", 10 | description="mingus is a music package for Python", 11 | long_description="""mingus is a package for Python used by programmers, musicians, \ 12 | composers and researchers to make and investigate music. At the core of mingus is music theory, \ 13 | which includes topics like intervals, chords, scales and progressions. These components are 14 | rigurously tested and can be used to generate and recognize musical elements using convenient 15 | shorthand where possible (for example some acceptable chords are: CM7, Am6, Ab7, G7). 16 | 17 | On top of that are several packages that deal with classical notation, MIDI (sequencing, \ 18 | loading and saving), MusicXML, ASCII tablature, and many other useful and plain cool things \ 19 | like LilyPond and FluidSynth support. Everything is fully documentated, put into simple \ 20 | APIs and has a tutorial making it easy to jump straight in. 21 | """, 22 | author="Bart Spaans", 23 | author_email="bart.spaans@gmail.com", 24 | url="https://github.com/bspaans/python-mingus", 25 | packages=[ 26 | "mingus", 27 | "mingus.core", 28 | "mingus.containers", 29 | "mingus.extra", 30 | "mingus.midi", 31 | ], 32 | data_files=[ 33 | ( 34 | "mingus_examples/pygame-drum", 35 | [ 36 | "mingus_examples/pygame-drum/pad.png", 37 | "mingus_examples/pygame-drum/pygame-drum.py", 38 | ], 39 | ), 40 | ( 41 | "mingus_examples/pygame-piano", 42 | [ 43 | "mingus_examples/pygame-piano/pygame-piano.py", 44 | "mingus_examples/pygame-piano/keys.png", 45 | ], 46 | ), 47 | ], 48 | install_requires=["six",], 49 | extras_require={ 50 | "fft": ["numpy"], 51 | "fluidsynth": ["numpy"], 52 | }, 53 | license="GPLv3", 54 | classifiers=[ 55 | "Intended Audience :: Developers", 56 | "Intended Audience :: Science/Research", 57 | "Intended Audience :: Other Audience", 58 | "License :: OSI Approved :: GNU General Public License (GPL)", 59 | "Operating System :: OS Independent", 60 | "Programming Language :: Python", 61 | "Programming Language :: Python :: 2.7", 62 | "Programming Language :: Python :: 3.4", 63 | "Programming Language :: Python :: 3.5", 64 | "Programming Language :: Python :: 3.6", 65 | "Programming Language :: Python :: 3.7", 66 | "Programming Language :: Python :: 3.8", 67 | "Topic :: Artistic Software", 68 | "Topic :: Education", 69 | "Topic :: Multimedia", 70 | "Topic :: Multimedia :: Graphics :: Presentation", 71 | "Topic :: Multimedia :: Sound/Audio", 72 | "Topic :: Multimedia :: Sound/Audio :: MIDI", 73 | "Topic :: Multimedia :: Sound/Audio :: Analysis", 74 | "Topic :: Scientific/Engineering :: Information Analysis", 75 | "Topic :: Scientific/Engineering :: Visualization", 76 | "Topic :: Software Development :: Libraries :: Python Modules", 77 | ], 78 | ) 79 | -------------------------------------------------------------------------------- /unittest/440_880_clean.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/unittest/440_880_clean.wav -------------------------------------------------------------------------------- /unittest/440_sine_clean.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/unittest/440_sine_clean.wav -------------------------------------------------------------------------------- /unittest/example.sf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edudobay/python-mingus/9a991481b31cb94a4339c06176d51d15a99429dc/unittest/example.sf2 -------------------------------------------------------------------------------- /unittest/run_fluidsynth_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # mingus - Music theory Python package, run_fluidsynth_tests module. 5 | # Copyright (C) 2008, Bart Spaans 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | """Separated fluidsynth tests. 21 | 22 | Remember: you need a running fluidsynth server process listening at port 23 | 9800 to pass this test. 24 | """ 25 | from __future__ import absolute_import 26 | 27 | import unittest 28 | import test_fluidsynth 29 | 30 | suite = unittest.TestSuite([test_fluidsynth.suite()]) 31 | unittest.TextTestRunner(verbosity=2).run(suite) 32 | -------------------------------------------------------------------------------- /unittest/run_lilypond_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # mingus - Music theory Python package, run_lilypond_tests module. 5 | # Copyright (C) 2008, Bart Spaans 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | """Separated LilyPond tests.""" 21 | from __future__ import absolute_import 22 | 23 | import unittest 24 | import test_lilypond 25 | 26 | suite = unittest.TestSuite([test_lilypond.suite()]) 27 | unittest.TextTestRunner(verbosity=2).run(suite) 28 | -------------------------------------------------------------------------------- /unittest/run_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # mingus - Music theory Python package, run_tests module. 5 | # Copyright (C) 2008, Bart Spaans 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | """Test suite for the music theory package. 21 | 22 | Invoke this file from the command line, from within the 'unittest' directory 23 | to run all the testcases. 24 | """ 25 | from __future__ import absolute_import 26 | 27 | import unittest 28 | 29 | import test_notes 30 | import test_keys 31 | import test_intervals 32 | import test_chords 33 | import test_scales 34 | import test_meter 35 | import test_progressions 36 | import test_value 37 | 38 | # mingus.containers Tests 39 | 40 | import test_note 41 | import test_note_containers 42 | import test_instrument 43 | import test_bar 44 | import test_track 45 | import test_composition 46 | import test_suite 47 | 48 | # MIDI TESTS HERE ... 49 | 50 | import test_fft 51 | import test_tablature 52 | import test_tunings 53 | import test_musicxml 54 | 55 | # See run_fluidsynth_tests.py for FluidSynth audio tests See 56 | # run_lilypond_tests.py to generate some pdf's 57 | # 58 | # Add new suites here... 59 | 60 | core = [ 61 | test_notes, 62 | test_keys, 63 | test_intervals, 64 | test_chords, 65 | test_scales, 66 | test_meter, 67 | test_progressions, 68 | test_value, 69 | ] 70 | containers = [ 71 | test_note, 72 | test_note_containers, 73 | test_instrument, 74 | test_bar, 75 | test_track, 76 | test_composition, 77 | test_suite, 78 | ] 79 | extra = [test_fft, test_tunings, test_tablature, test_musicxml] 80 | 81 | # Run all tests 82 | 83 | suite = unittest.TestSuite([x.suite() for x in core + containers + extra]) 84 | unittest.TextTestRunner(verbosity=2).run(suite) 85 | -------------------------------------------------------------------------------- /unittest/test_bar.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | from mingus.core.keys import Key 8 | from mingus.containers.bar import Bar 9 | from mingus.containers.note import Note 10 | from mingus.containers.note_container import NoteContainer 11 | from mingus.containers.mt_exceptions import MeterFormatError 12 | import unittest 13 | 14 | 15 | class test_Bar(unittest.TestCase): 16 | def setUp(self): 17 | self.b = Bar("C", (4, 4)) 18 | self.c = Bar("E", (2, 2)) 19 | self.meterless = Bar("C", (0, 0)) 20 | 21 | def test_place_notes_types(self): 22 | self.assertEqual(True, self.meterless + NoteContainer(["A", "C"])) 23 | self.assertEqual(True, self.meterless + "A") 24 | self.assertEqual(True, self.meterless + Note("A")) 25 | self.assertEqual(True, self.meterless + ["A", "B"]) 26 | self.assertEqual(True, self.meterless + [Note("A"), Note("B")]) 27 | 28 | def test_get_range(self): 29 | self.b + NoteContainer(["C", "E"]) 30 | self.assertEqual((Note("C"), Note("E")), self.b.get_range()) 31 | 32 | def test_set_item(self): 33 | b = Bar() 34 | b + ["A", "C", "E"] 35 | c = Bar() 36 | c + ["A", "C", "E"] 37 | self.assertEqual(b, c) 38 | c[0] = NoteContainer(["A", "C", "E"]) 39 | self.assertEqual(b, c) 40 | c[0] = ["A", "C", "E"] 41 | self.assertEqual(b, c) 42 | c[0] = Note("A") 43 | c[0] = c[0][2] + NoteContainer(["C", "E"]) 44 | self.assertEqual(b, c) 45 | c[0] = Note("A") 46 | c[0] = c[0][2] + "C" 47 | c[0] = c[0][2] + "E" 48 | self.assertEqual(b, c) 49 | 50 | def test_key(self): 51 | self.assertEqual(self.b.key, Key("C")) 52 | self.assertEqual(self.c.key, Key("E")) 53 | 54 | def test_transpose(self): 55 | b = Bar() 56 | c = Bar() 57 | b + ["C", "E", "G"] 58 | c + ["E", "G#", "B"] 59 | b + ["F", "A", "C"] 60 | c + ["A", "C#", "E"] 61 | b.transpose("3", True) 62 | self.assertEqual(b, c) 63 | b.transpose("3", False) 64 | b.transpose("3") 65 | self.assertEqual(b, c) 66 | 67 | def test_augment(self): 68 | b = Bar() 69 | c = Bar() 70 | d = Bar() 71 | b + "A" 72 | c + "A#" 73 | d + "A##" 74 | b.augment() 75 | self.assertEqual(b, c) 76 | b.augment() 77 | self.assertEqual(b, d) 78 | c.augment() 79 | self.assertEqual(c, d) 80 | 81 | def test_diminish(self): 82 | b = Bar() 83 | c = Bar() 84 | b + "A" 85 | c + "Ab" 86 | b.diminish() 87 | self.assertEqual(b, c) 88 | 89 | # def test_to_minor(self): 90 | # b = Bar() 91 | # c = Bar() 92 | # b + 'C' 93 | # c + 'A' 94 | # b.to_minor() 95 | # self.assertEqual(b, c) 96 | # 97 | # def test_to_major(self): 98 | # b = Bar() 99 | # c = Bar() 100 | # b + 'C' 101 | # c + 'A' 102 | # c.to_major() 103 | # self.assertEqual(b, c) 104 | 105 | def test_get_note_names(self): 106 | b = Bar() 107 | b + "C" 108 | b + "A" 109 | self.assertEqual(["C", "A"], b.get_note_names()) 110 | 111 | def test_determine_chords(self): 112 | b = Bar() 113 | b + ["C", "E", "G"] 114 | b + ["F", "A", "C"] 115 | self.assertEqual( 116 | [[0.0, ["C major triad"]], [0.25, ["F major triad"]]], b.determine_chords() 117 | ) 118 | 119 | def test_determine_progression(self): 120 | b = Bar() 121 | b + ["C", "E", "G"] 122 | b + ["F", "A", "C"] 123 | self.assertEqual([[0.0, ["I"]], [0.25, ["IV"]]], b.determine_progression(True)) 124 | 125 | 126 | def suite(): 127 | return unittest.TestLoader().loadTestsFromTestCase(test_Bar) 128 | -------------------------------------------------------------------------------- /unittest/test_composition.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | from mingus.containers.composition import Composition 8 | import unittest 9 | 10 | 11 | class test_Composition(unittest.TestCase): 12 | def setUp(self): 13 | pass 14 | 15 | 16 | def suite(): 17 | return unittest.TestLoader().loadTestsFromTestCase(test_Composition) 18 | -------------------------------------------------------------------------------- /unittest/test_fft.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | import unittest 8 | import mingus.extra.fft as fft 9 | from mingus.containers import * 10 | 11 | 12 | class test_fft(unittest.TestCase): 13 | def setUp(self): 14 | (self.data, self.freq, self.bits) = fft.data_from_file("440_sine_clean.wav") 15 | 16 | def test_find_Note(self): 17 | self.assertEqual(Note("A"), fft.find_Note(self.data, self.freq, self.bits)) 18 | 19 | def test_find_melody(self): 20 | self.assertEqual( 21 | [(Note("A-4"), 86), (Note("A-5"), 86)], 22 | fft.find_melody("440_880_clean.wav", 512)[:2], 23 | ) 24 | 25 | 26 | def suite(): 27 | return unittest.TestLoader().loadTestsFromTestCase(test_fft) 28 | -------------------------------------------------------------------------------- /unittest/test_instrument.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | from mingus.containers.instrument import Instrument, Piano, Guitar 8 | from mingus.containers.note_container import NoteContainer 9 | import unittest 10 | 11 | 12 | class test_Instrument(unittest.TestCase): 13 | def setUp(self): 14 | self.i = Instrument() 15 | self.p = Piano() 16 | self.g = Guitar() 17 | self.notes = NoteContainer(["A", "B", "C", "D", "E"]) 18 | self.noteslow = NoteContainer(["C-0", "D-0", "E-0"]) 19 | self.noteshigh = NoteContainer(["A-12", "B-12", "C-12", "D-12", "E-12"]) 20 | 21 | def test_note_in_range(self): 22 | for x in self.notes: 23 | self.assertTrue(self.i.note_in_range(x)) 24 | self.assertTrue(self.p.note_in_range(x)) 25 | self.assertTrue(self.g.note_in_range(x)) 26 | for x in self.noteslow + self.noteshigh: 27 | self.assertEqual( 28 | False, 29 | self.p.note_in_range(x), 30 | "%s should not be able to be played by a Piano" % x, 31 | ) 32 | self.assertEqual( 33 | False, 34 | self.g.note_in_range(x), 35 | "%s should not be able to be played by a Guitar" % x, 36 | ) 37 | 38 | def test_can_play_notes(self): 39 | self.assertTrue(self.i.can_play_notes(self.notes)) 40 | self.assertTrue(self.p.can_play_notes(self.notes)) 41 | self.assertTrue(self.g.can_play_notes(self.notes)) 42 | self.assertEqual(False, self.p.can_play_notes(self.noteslow)) 43 | self.assertEqual(False, self.g.can_play_notes(self.noteslow)) 44 | self.assertEqual(False, self.p.can_play_notes(self.noteshigh)) 45 | self.assertEqual(False, self.g.can_play_notes(self.noteshigh)) 46 | self.assertEqual( 47 | False, 48 | self.g.can_play_notes(NoteContainer(["A", "B", "C", "D", "E", "F", "G",])), 49 | ) 50 | 51 | 52 | def suite(): 53 | return unittest.TestLoader().loadTestsFromTestCase(test_Instrument) 54 | -------------------------------------------------------------------------------- /unittest/test_keys.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | import mingus.core.keys as keys 8 | from mingus.core.mt_exceptions import NoteFormatError, KeyError 9 | import unittest 10 | 11 | 12 | class test_keys(unittest.TestCase): 13 | def setUp(self): 14 | self.scale = { 15 | "C": ["C", "D", "E", "F", "G", "A", "B"], 16 | "F": ["F", "G", "A", "Bb", "C", "D", "E"], 17 | "d#": ["D#", "E#", "F#", "G#", "A#", "B", "C#"], 18 | } 19 | 20 | def test_get_key(self): 21 | self.assertEqual(("C", "a"), keys.get_key()) 22 | self.assertEqual(("C", "a"), keys.get_key(0)) 23 | self.assertEqual(("Eb", "c"), keys.get_key(-3)) 24 | self.assertEqual(("C#", "a#"), keys.get_key(7)) 25 | 26 | def test_get_key_signature(self): 27 | self.assertEqual(0, keys.get_key_signature()) 28 | self.assertEqual(0, keys.get_key_signature("a")) 29 | self.assertEqual(-3, keys.get_key_signature("Eb")) 30 | self.assertEqual(7, keys.get_key_signature("a#")) 31 | 32 | def test_get_key_signature_accidentals(self): 33 | self.assertEqual([], keys.get_key_signature_accidentals()) 34 | self.assertEqual([], keys.get_key_signature_accidentals("C")) 35 | self.assertEqual( 36 | ["Bb", "Eb", "Ab", "Db", "Gb", "Cb", "Fb"], 37 | keys.get_key_signature_accidentals("Cb"), 38 | ) 39 | 40 | def test_get_notes(self): 41 | for k in self.scale: 42 | self.assertEqual( 43 | self.scale[k], 44 | keys.get_notes(k), 45 | "Invalid notes for key %s" % self.scale[k], 46 | ) 47 | 48 | def test_relative_major(self): 49 | known = { 50 | "c": "Eb", 51 | "a": "C", 52 | "e": "G", 53 | "f": "Ab", 54 | "d": "F", 55 | "b": "D", 56 | } 57 | for k in known: 58 | self.assertEqual( 59 | known[k], 60 | keys.relative_major(k), 61 | "The major of %s is not %s, expecting %s" 62 | % (k, keys.relative_major(k), known[k]), 63 | ) 64 | 65 | def test_relative_minor(self): 66 | known = {"C": "a", "E": "c#", "B": "g#", "G": "e", "F": "d"} 67 | for k in known: 68 | self.assertEqual( 69 | known[k], 70 | keys.relative_minor(k), 71 | "The minor of %s is not %s, expecting %s" 72 | % (k, keys.relative_minor(k), known[k]), 73 | ) 74 | 75 | 76 | def suite(): 77 | return unittest.TestLoader().loadTestsFromTestCase(test_keys) 78 | -------------------------------------------------------------------------------- /unittest/test_meter.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | import mingus.core.meter as meter 8 | import unittest 9 | from six.moves import range 10 | 11 | 12 | class test_meter(unittest.TestCase): 13 | def setUp(self): 14 | self.simple_meters = [ 15 | (2, 4), 16 | (3, 4), 17 | (4, 4), 18 | (6, 4), 19 | (8, 4), 20 | (5, 4), 21 | (2, 2), 22 | (1, 2), 23 | (6, 4), 24 | ] 25 | self.compound_meters = [ 26 | (6, 4), 27 | (9, 4), 28 | (12, 4), 29 | (6, 8), 30 | (9, 8), 31 | (12, 8), 32 | (6, 16), 33 | (9, 16), 34 | (12, 16), 35 | ] 36 | self.asymmetrical_meters = [ 37 | (3, 4), 38 | (5, 4), 39 | (7, 4), 40 | (11, 4), 41 | (1, 8), 42 | (3, 8), 43 | (5, 8), 44 | (7, 8), 45 | (3, 16), 46 | (11, 16), 47 | (15, 16), 48 | (17, 16), 49 | ] 50 | 51 | def test_valid_beat_duration(self): 52 | for x in [ 53 | 1, 54 | 2, 55 | 4, 56 | 8, 57 | 16, 58 | 32, 59 | 64, 60 | 128, 61 | 256, 62 | 512, 63 | 1024, 64 | 2048, 65 | ]: 66 | self.assertTrue( 67 | meter.valid_beat_duration(x), "%d should be a valid beat duration" % x 68 | ) 69 | 70 | def test_invalid_beat_duration(self): 71 | for x in [0, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15,] + list(range(17, 31)): 72 | self.assertTrue( 73 | not meter.valid_beat_duration(x), 74 | "%d should not be a valid beat duration" % x, 75 | ) 76 | 77 | def test_is_compound(self): 78 | for x in self.compound_meters: 79 | self.assertTrue( 80 | meter.is_compound(x), "%d/%d should be a compound meter" % x 81 | ) 82 | 83 | def test_is_simple(self): 84 | for x in self.simple_meters: 85 | self.assertTrue(meter.is_simple(x), "%d/%d should be a simple meter" % x) 86 | 87 | def test_is_valid_meter(self): 88 | for x in self.compound_meters + self.simple_meters: 89 | self.assertTrue(meter.is_valid(x), "%d/%d should be a valid meter" % x) 90 | 91 | def test_is_asymmetrical(self): 92 | for x in self.asymmetrical_meters: 93 | self.assertTrue( 94 | meter.is_asymmetrical(x), "%d/%d should be a asymmetrical meter" % x 95 | ) 96 | 97 | def test_is_full(self): 98 | pass 99 | 100 | 101 | def suite(): 102 | return unittest.TestLoader().loadTestsFromTestCase(test_meter) 103 | -------------------------------------------------------------------------------- /unittest/test_musicxml.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import sys 3 | 4 | sys.path += ["../"] 5 | 6 | import mingus.extra.musicxml as mxl 7 | import unittest 8 | 9 | 10 | class test_MusicXML(unittest.TestCase): 11 | def setUp(self): 12 | pass 13 | 14 | 15 | def suite(): 16 | return unittest.TestLoader().loadTestsFromTestCase(test_MusicXML) 17 | -------------------------------------------------------------------------------- /unittest/test_note.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | from mingus.containers.note import Note 8 | import unittest 9 | from mingus.containers.mt_exceptions import NoteFormatError 10 | 11 | 12 | class test_Note(unittest.TestCase): 13 | def setUp(self): 14 | self.c = Note("C", 5) 15 | self.c1 = Note("C") 16 | self.c2 = Note("C", 3) 17 | self.b4 = Note("B", 4) 18 | self.b5 = Note("B", 5) 19 | 20 | def test_cmp(self): 21 | self.assertTrue(self.c1 <= self.b5) 22 | self.assertTrue(self.c < self.b5) 23 | self.assertTrue(self.c1 < self.b5) 24 | self.assertTrue(self.c2 < self.b5) 25 | self.assertTrue(self.c > self.b4, "%s %s" % (self.c, self.b4)) 26 | self.assertTrue(self.c1 < self.b4) 27 | self.assertTrue(self.c2 < self.b4) 28 | self.assertTrue(self.b4 < self.b5) 29 | self.assertTrue(Note("C") > Note("Cb")) 30 | self.assertTrue(self.c > None) 31 | 32 | def test_eq(self): 33 | self.assertTrue(self.c != self.c1) 34 | self.assertTrue(self.c == self.c) 35 | self.assertTrue(Note("C") == Note("C")) 36 | self.assertTrue(self.c != None) 37 | 38 | def test_to_int(self): 39 | self.assertEqual(48, Note("C", 4)) 40 | self.assertEqual(47, Note("Cb", 4)) 41 | self.assertEqual(36, int(self.c2)) 42 | self.assertEqual(71, int(self.b5)) 43 | self.assertEqual(59, int(self.b4)) 44 | 45 | def test_set_note(self): 46 | n = Note() 47 | self.assertTrue(n.set_note("C", 5, {})) 48 | n.empty() 49 | self.assertTrue(n.set_note("C-5")) 50 | self.assertTrue(n.set_note("C", 5)) 51 | self.assertTrue(n.set_note("C#-12", 5)) 52 | self.assertRaises(NoteFormatError, n.set_note, "H") 53 | self.assertRaises(NoteFormatError, n.set_note, "C 23") 54 | self.assertRaises(NoteFormatError, n.set_note, "C# 123") 55 | 56 | def test_to_hertz(self): 57 | self.assertEqual(Note("A", 0).to_hertz(), 27.5) 58 | self.assertEqual(Note("A", 1).to_hertz(), 55) 59 | self.assertEqual(Note("A", 2).to_hertz(), 110) 60 | self.assertEqual(Note("A", 3).to_hertz(), 220) 61 | self.assertEqual(Note("A", 4).to_hertz(), 440) 62 | self.assertEqual(Note("A", 5).to_hertz(), 880) 63 | self.assertEqual(Note("A", 6).to_hertz(), 1760) 64 | 65 | def test_from_hertz(self): 66 | a = Note() 67 | self.assertEqual(a.from_hertz(55.5), Note("A", 1)) 68 | self.assertEqual(a.from_hertz(110), Note("A", 2)) 69 | a.from_hertz(220) 70 | self.assertEqual(a, Note("A", 3)) 71 | a.from_hertz(440) 72 | self.assertEqual(a, Note("A", 4)) 73 | a.from_hertz(880) 74 | self.assertEqual(a, Note("A", 5)) 75 | a.from_hertz(1760) 76 | self.assertEqual(a, Note("A", 6)) 77 | 78 | def test_transpose(self): 79 | a = Note("C") 80 | a.transpose("3") 81 | self.assertEqual(Note("E"), a) 82 | a.transpose("b2") 83 | self.assertEqual(Note("F"), a) 84 | a.transpose("5") 85 | self.assertEqual(Note("C", 5), a) 86 | a.transpose("5", False) 87 | self.assertEqual(Note("F"), a) 88 | a = Note("G-5") 89 | a.transpose("5") 90 | self.assertEqual(Note("D-6"), a) 91 | a.transpose("5", False) 92 | self.assertEqual(Note("G-5"), a) 93 | a.transpose("5", False) 94 | self.assertEqual(Note("C-5"), a) 95 | 96 | def test_from_int(self): 97 | self.assertEqual(Note("C", 0), Note().from_int(0)) 98 | self.assertEqual(Note("C", 1), Note().from_int(12)) 99 | 100 | def test_measure(self): 101 | self.assertTrue(Note("C").measure(Note("D")) == 2) 102 | self.assertTrue(Note("D").measure(Note("C")) == -2) 103 | 104 | def test_to_shorthand(self): 105 | self.assertTrue(Note("C-0").to_shorthand() == "C,,") 106 | self.assertTrue(Note("C-2").to_shorthand() == "C") 107 | self.assertTrue(Note("C-3").to_shorthand() == "c") 108 | self.assertTrue(Note("C-4").to_shorthand() == "c'") 109 | self.assertTrue(Note("C-9").to_shorthand() == "c''''''") 110 | 111 | def test_from_shorthand(self): 112 | self.assertTrue(Note().from_shorthand("C,,") == Note("C-0")) 113 | self.assertTrue(Note().from_shorthand("C") == Note("C-2")) 114 | self.assertTrue(Note().from_shorthand("c") == Note("C-3")) 115 | self.assertTrue(Note().from_shorthand("c'") == Note("C-4")) 116 | self.assertTrue(Note().from_shorthand("c''''''") == Note("C-9")) 117 | 118 | 119 | def suite(): 120 | return unittest.TestLoader().loadTestsFromTestCase(test_Note) 121 | -------------------------------------------------------------------------------- /unittest/test_notes.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | from six.moves import map 6 | 7 | sys.path = ["../"] + sys.path 8 | import mingus.core.notes as notes 9 | from mingus.core.mt_exceptions import RangeError 10 | import unittest 11 | 12 | 13 | class test_notes(unittest.TestCase): 14 | def setUp(self): 15 | self.base_notes = ["C", "D", "E", "F", "G", "A", "B"] 16 | self.sharps = [x + "#" for x in self.base_notes] 17 | self.flats = [x + "b" for x in self.base_notes] 18 | self.exotic = [x + "b###b#" for x in self.base_notes] 19 | 20 | def test_base_note_validity(self): 21 | for x in self.base_notes: 22 | self.assertTrue(notes.is_valid_note(x), "Base notes A-G") 23 | 24 | def test_sharp_note_validity(self): 25 | for x in self.sharps: 26 | self.assertTrue(notes.is_valid_note(x), "Sharp notes A#-G#") 27 | 28 | def test_flat_note_validity(self): 29 | for x in self.flats: 30 | self.assertTrue(notes.is_valid_note(x), "Flat notes Ab-Gb") 31 | 32 | def test_exotic_note_validity(self): 33 | for x in self.exotic: 34 | self.assertTrue(notes.is_valid_note(x), "Exotic notes Ab##b#-Gb###b#") 35 | 36 | def test_faulty_note_invalidity(self): 37 | for x in ["asdasd", "C###f", "c", "d", "E*"]: 38 | self.assertEqual(False, notes.is_valid_note(x), "Faulty notes") 39 | 40 | def test_int_to_note(self): 41 | known = { 42 | (0, "#"): "C", 43 | (3, "#"): "D#", 44 | (8, "#"): "G#", 45 | (11, "#"): "B", 46 | (0, "b"): "C", 47 | (3, "b"): "Eb", 48 | (8, "b"): "Ab", 49 | (11, "b"): "B", 50 | } 51 | for k in known: 52 | self.assertEqual( 53 | known[k], 54 | notes.int_to_note(k[0], k[1]), 55 | '%s with "%s" not corrisponding to %s, expecting %s' 56 | % (k[0], k[1], notes.int_to_note(k[0], k[1]), known[k]), 57 | ) 58 | 59 | def test_invalid_int_to_note(self): 60 | faulty = [-1, 12, 13, 123123, -123] 61 | for x in faulty: 62 | self.assertRaises(RangeError, notes.int_to_note, x) 63 | 64 | def test_reduce_accidentals(self): 65 | known = { 66 | "C": "C", 67 | "F#": "F#", 68 | "Bb": "Bb", 69 | "G##": "A", 70 | "Abb": "G", 71 | "B##": "C#", 72 | "C####": "E", 73 | } 74 | for k in known: 75 | self.assertEqual( 76 | known[k], 77 | notes.reduce_accidentals(k), 78 | "The reduced note of %s is not %s, expecting %s" 79 | % (k, notes.reduce_accidentals(k), known[k]), 80 | ) 81 | 82 | def test_remove_redundant_accidentals(self): 83 | known = {"C##b": "C#", "Eb##b": "E"} 84 | for k in known: 85 | self.assertEqual( 86 | known[k], 87 | notes.remove_redundant_accidentals(k), 88 | "The simplified note of %s is not %s, expecting %s" 89 | % (k, notes.remove_redundant_accidentals(k), known[k]), 90 | ) 91 | 92 | def test_augment(self): 93 | known = {"C": "C#", "C#": "C##", "Cb": "C", "Cbb": "Cb"} 94 | for x in known: 95 | self.assertEqual( 96 | known[x], 97 | notes.augment(x), 98 | "The augmented note of %s is not %s, expecting %s" 99 | % (x, notes.augment(x), known[x]), 100 | ) 101 | 102 | def test_diminish(self): 103 | known = {"C": "Cb", "C#": "C", "C##": "C#", "Cb": "Cbb"} 104 | for x in known: 105 | self.assertEqual( 106 | known[x], 107 | notes.diminish(x), 108 | "The diminished note of %s is not %s, expecting %s" 109 | % (x, notes.diminish(x), known[x]), 110 | ) 111 | 112 | 113 | def suite(): 114 | return unittest.TestLoader().loadTestsFromTestCase(test_notes) 115 | -------------------------------------------------------------------------------- /unittest/test_suite.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | from mingus.containers.suite import Suite 8 | import unittest 9 | 10 | 11 | class test_Suite(unittest.TestCase): 12 | def setUp(self): 13 | pass 14 | 15 | 16 | def suite(): 17 | return unittest.TestLoader().loadTestsFromTestCase(test_Suite) 18 | -------------------------------------------------------------------------------- /unittest/test_tablature.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | import mingus.extra.tablature as tablature 8 | import mingus.extra.tunings as tunings 9 | import unittest 10 | 11 | 12 | class test_Tablature(unittest.TestCase): 13 | def setUp(self): 14 | self.guitar = tunings.get_tuning("Guitar", "standard", 6, 1) 15 | 16 | def test__get_qsize(self): 17 | self.assertTrue(tablature._get_qsize(self.guitar, 4) == 0) 18 | 19 | 20 | def suite(): 21 | return unittest.TestLoader().loadTestsFromTestCase(test_Tablature) 22 | -------------------------------------------------------------------------------- /unittest/test_track.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | from mingus.containers.track import Track 8 | from mingus.containers.bar import Bar 9 | from mingus.containers.instrument import Instrument, Piano, Guitar 10 | import unittest 11 | 12 | 13 | class test_Track(unittest.TestCase): 14 | def setUp(self): 15 | self.i = Track(Instrument()) 16 | self.p = Track(Piano()) 17 | self.g = Track(Guitar()) 18 | self.tr = Track() 19 | 20 | def test_add(self): 21 | pass 22 | 23 | def test_transpose(self): 24 | t = Track() 25 | t + "C" 26 | t + "E" 27 | t.transpose("3") 28 | s = Track() 29 | s + "E" 30 | s + "G#" 31 | self.assertEqual(s, t) 32 | 33 | 34 | def suite(): 35 | return unittest.TestLoader().loadTestsFromTestCase(test_Track) 36 | -------------------------------------------------------------------------------- /unittest/test_tunings.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import sys 5 | 6 | sys.path += ["../"] 7 | import mingus.extra.tunings as tunings 8 | from mingus.containers.note import Note 9 | from mingus.core.mt_exceptions import RangeError 10 | import unittest 11 | 12 | 13 | class test_Tunings(unittest.TestCase): 14 | def setUp(self): 15 | self.guitar6 = tunings.get_tuning("guitar", "Standard", 6, 1) 16 | self.guitar12 = tunings.get_tuning("guitar", "Standard", 6, 2) 17 | 18 | def test_get_tuning(self): 19 | self.assertTrue(tunings.get_tuning("guitar", "Standard").instrument == "Guitar") 20 | 21 | def test_get_tunings(self): 22 | self.assertTrue(tunings.get_tunings("Guitar")[0].instrument == "Guitar") 23 | self.assertTrue( 24 | tunings.get_tunings("Bass guitar")[0].instrument == "Bass guitar" 25 | ) 26 | self.assertTrue( 27 | tunings.get_tunings("Bass guita")[0].instrument == "Bass guitar" 28 | ) 29 | self.assertTrue(tunings.get_tunings("Bass")[0].instrument == "Bass guitar") 30 | self.assertTrue( 31 | "Bass guitar" in [x.instrument for x in tunings.get_tunings("b")] 32 | ) 33 | self.assertTrue( 34 | "Banjo (bass)" in [x.instrument for x in tunings.get_tunings("b")] 35 | ) 36 | 37 | def test_count_strings(self): 38 | self.assertTrue(self.guitar6.count_strings() == 6) 39 | self.assertTrue(self.guitar12.count_strings() == 6) 40 | 41 | def test_count_courses(self): 42 | self.assertTrue(self.guitar6.count_courses() == 1.0) 43 | self.assertTrue(self.guitar12.count_courses() == 2.0) 44 | 45 | def test_find_frets(self): 46 | self.assertTrue( 47 | self.guitar6.find_frets("E-1") == [None, None, None, None, None, None,] 48 | ) 49 | self.assertTrue( 50 | self.guitar6.find_frets("E-2") == [0, None, None, None, None, None,] 51 | ) 52 | self.assertTrue( 53 | self.guitar6.find_frets("A-2") == [5, 0, None, None, None, None,] 54 | ) 55 | self.assertTrue( 56 | self.guitar6.find_frets("D-3") == [10, 5, 0, None, None, None,] 57 | ) 58 | self.assertTrue( 59 | self.guitar6.find_frets("G-3") == [15, 10, 5, 0, None, None,] 60 | ) 61 | self.assertTrue( 62 | self.guitar6.find_frets("B-3") == [19, 14, 9, 4, 0, None,] 63 | ) 64 | self.assertTrue( 65 | self.guitar6.find_frets("E-4") == [24, 19, 14, 9, 5, 0,] 66 | ) 67 | self.assertTrue( 68 | self.guitar6.find_frets("E-4", 18) == [None, None, 14, 9, 5, 0,] 69 | ) 70 | 71 | def test_find_fingering(self): 72 | self.assertTrue([(0, 0), (1, 0)] in self.guitar6.find_fingering(["E-2", "A-2"])) 73 | self.assertTrue( 74 | [(5, 0), (4, 12)] in self.guitar6.find_fingering(["E-4", "B-4"]) 75 | ) 76 | 77 | def test_get_Note(self): 78 | self.assertTrue(self.guitar6.get_Note(0, 0) == Note("E-2")) 79 | self.assertTrue(self.guitar6.get_Note(1, 0) == Note("A-2")) 80 | self.assertTrue(self.guitar6.get_Note(2, 0) == Note("D-3")) 81 | self.assertTrue(self.guitar6.get_Note(3, 0) == Note("G-3")) 82 | self.assertTrue(self.guitar6.get_Note(3, 3) == Note("A#-3")) 83 | self.assertRaises(RangeError, self.guitar6.get_Note, -1, 3) 84 | self.assertRaises(RangeError, self.guitar6.get_Note, 7, 3) 85 | self.assertRaises(RangeError, self.guitar6.get_Note, 3, -1) 86 | self.assertRaises(RangeError, self.guitar6.get_Note, 3, 25) 87 | 88 | 89 | def suite(): 90 | return unittest.TestLoader().loadTestsFromTestCase(test_Tunings) 91 | -------------------------------------------------------------------------------- /unittest/test_value.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # -*- coding: utf-8 -*- 4 | import mingus.core.value as value 5 | import unittest 6 | 7 | 8 | class test_value(unittest.TestCase): 9 | def setUp(self): 10 | pass 11 | 12 | def test_add(self): 13 | self.assertEqual(value.add(4, 4), 2) 14 | self.assertEqual(value.add(4, 8), 8 / 3.0) 15 | self.assertEqual(value.add(8, 4), 8 / 3.0) 16 | 17 | def test_dots(self): 18 | self.assertEqual(value.dots(4, 0), 4) 19 | self.assertEqual(value.dots(4, 1), 8 / 3.0) 20 | self.assertEqual(value.dots(4, 1), value.add(8, 4)) 21 | self.assertEqual(value.dots(4, 2), value.add(value.add(8, 4), 16)) 22 | self.assertEqual(value.dots(8, 0), 8) 23 | self.assertEqual(value.dots(8, 1), 16 / 3.0) 24 | self.assertEqual(value.dots(8, 1), value.add(8, 16)) 25 | self.assertEqual(value.dots(8, 2), value.add(value.add(8, 16), 32)) 26 | 27 | def test_determine(self): 28 | self.assertEqual(value.determine(7), (4, 0, 7, 4)) 29 | self.assertEqual(value.determine(8), (8, 0, 1, 1)) 30 | self.assertEqual(value.determine(10), (8, 0, 5, 4)) 31 | self.assertEqual(value.determine(12), (8, 0, 3, 2)) 32 | self.assertEqual(value.determine(14), (8, 0, 7, 4)) 33 | for x in value.base_values: 34 | self.assertEqual(value.determine(x), (x, 0, 1, 1)) 35 | self.assertEqual(value.determine(value.dots(x, 1)), (x, 1, 1, 1)) 36 | self.assertEqual(value.determine(value.dots(x, 2)), (x, 2, 1, 1)) 37 | self.assertEqual(value.determine(value.dots(x, 3)), (x, 3, 1, 1)) 38 | self.assertEqual(value.determine(value.dots(x, 4)), (x, 4, 1, 1)) 39 | for (s, x) in enumerate(value.base_triplets): 40 | self.assertEqual(value.determine(x), (value.base_values[s], 0, 3, 2)) 41 | for (s, x) in enumerate(value.base_quintuplets): 42 | self.assertEqual(value.determine(x), (value.base_values[s], 0, 5, 4)) 43 | for (s, x) in enumerate(value.base_septuplets): 44 | self.assertEqual(value.determine(x), (value.base_values[s], 0, 7, 4)) 45 | 46 | def test_determine_imperfect(self): 47 | self.assertEqual(value.determine(9), (8, 0, 1, 1)) 48 | self.assertEqual(value.determine(4.5), (4, 0, 1, 1)) 49 | 50 | def test_triplet(self): 51 | self.assertEqual(value.triplet(1), 1.5) 52 | self.assertEqual(value.triplet(2), 3) 53 | self.assertEqual(value.triplet(4), 6) 54 | self.assertEqual(value.triplet(8), 12) 55 | self.assertEqual(value.triplet(16), 24) 56 | self.assertEqual(value.triplet(32), 48) 57 | self.assertEqual(value.triplet(64), 96) 58 | self.assertEqual(value.triplet(128), 192) 59 | 60 | def test_quintuplet(self): 61 | self.assertEqual(value.quintuplet(1), 1.25) 62 | self.assertEqual(value.quintuplet(2), 2.5) 63 | self.assertEqual(value.quintuplet(4), 5) 64 | self.assertEqual(value.quintuplet(8), 10) 65 | self.assertEqual(value.quintuplet(16), 20) 66 | self.assertEqual(value.quintuplet(32), 40) 67 | self.assertEqual(value.quintuplet(64), 80) 68 | self.assertEqual(value.quintuplet(128), 160) 69 | 70 | def test_septuplet(self): 71 | self.assertEqual(value.septuplet(1), 1.75) 72 | self.assertEqual(value.septuplet(2), 3.5) 73 | self.assertEqual(value.septuplet(4), 7) 74 | self.assertEqual(value.septuplet(8), 14) 75 | self.assertEqual(value.septuplet(16), 28) 76 | self.assertEqual(value.septuplet(32), 56) 77 | self.assertEqual(value.septuplet(64), 112) 78 | self.assertEqual(value.septuplet(128), 224) 79 | self.assertEqual(value.septuplet(1, False), 0.875) 80 | self.assertEqual(value.septuplet(2, False), 1.75) 81 | self.assertEqual(value.septuplet(4, False), 3.5) 82 | self.assertEqual(value.septuplet(8, False), 7) 83 | self.assertEqual(value.septuplet(16, False), 14) 84 | self.assertEqual(value.septuplet(32, False), 28) 85 | self.assertEqual(value.septuplet(64, False), 56) 86 | self.assertEqual(value.septuplet(128, False), 112) 87 | 88 | 89 | def suite(): 90 | return unittest.TestLoader().loadTestsFromTestCase(test_value) 91 | --------------------------------------------------------------------------------