├── .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 |
--------------------------------------------------------------------------------