├── LICENSE ├── README.md ├── cpanfile ├── ex-01-01.pl ├── ex-01-02.pl ├── ex-01-03.pl ├── ex-01-04.pl ├── ex-02-01.pl ├── ex-02-02.pl ├── ex-03-01.pl ├── ex-03-02.pl ├── ex-04-01.pl ├── ex-04-02.pl ├── ex-04-03.pl ├── ex-04-04.pl ├── ex-05-01.pl ├── ex-05-02.pl ├── ex-06-01.pl ├── ex-06-02.pl ├── ex-06-03.pl ├── ex-07-01.pl ├── ex-08-01.pl ├── ex-08-02.pl ├── ex-08-03.pl ├── ex-08-04.pl ├── ex-08-05.pl └── ex-09-01.pl /LICENSE: -------------------------------------------------------------------------------- 1 | The Artistic License 2.0 2 | 3 | Copyright (c) 2000-2006, The Perl Foundation. 4 | 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | This license establishes the terms under which a given free software 11 | Package may be copied, modified, distributed, and/or redistributed. 12 | The intent is that the Copyright Holder maintains some artistic 13 | control over the development of that Package while still keeping the 14 | Package available as open source and free software. 15 | 16 | You are always permitted to make arrangements wholly outside of this 17 | license directly with the Copyright Holder of a given Package. If the 18 | terms of this license do not permit the full use that you propose to 19 | make of the Package, you should contact the Copyright Holder and seek 20 | a different licensing arrangement. 21 | 22 | Definitions 23 | 24 | "Copyright Holder" means the individual(s) or organization(s) 25 | named in the copyright notice for the entire Package. 26 | 27 | "Contributor" means any party that has contributed code or other 28 | material to the Package, in accordance with the Copyright Holder's 29 | procedures. 30 | 31 | "You" and "your" means any person who would like to copy, 32 | distribute, or modify the Package. 33 | 34 | "Package" means the collection of files distributed by the 35 | Copyright Holder, and derivatives of that collection and/or of 36 | those files. A given Package may consist of either the Standard 37 | Version, or a Modified Version. 38 | 39 | "Distribute" means providing a copy of the Package or making it 40 | accessible to anyone else, or in the case of a company or 41 | organization, to others outside of your company or organization. 42 | 43 | "Distributor Fee" means any fee that you charge for Distributing 44 | this Package or providing support for this Package to another 45 | party. It does not mean licensing fees. 46 | 47 | "Standard Version" refers to the Package if it has not been 48 | modified, or has been modified only in ways explicitly requested 49 | by the Copyright Holder. 50 | 51 | "Modified Version" means the Package, if it has been changed, and 52 | such changes were not explicitly requested by the Copyright 53 | Holder. 54 | 55 | "Original License" means this Artistic License as Distributed with 56 | the Standard Version of the Package, in its current version or as 57 | it may be modified by The Perl Foundation in the future. 58 | 59 | "Source" form means the source code, documentation source, and 60 | configuration files for the Package. 61 | 62 | "Compiled" form means the compiled bytecode, object code, binary, 63 | or any other form resulting from mechanical transformation or 64 | translation of the Source form. 65 | 66 | 67 | Permission for Use and Modification Without Distribution 68 | 69 | (1) You are permitted to use the Standard Version and create and use 70 | Modified Versions for any purpose without restriction, provided that 71 | you do not Distribute the Modified Version. 72 | 73 | 74 | Permissions for Redistribution of the Standard Version 75 | 76 | (2) You may Distribute verbatim copies of the Source form of the 77 | Standard Version of this Package in any medium without restriction, 78 | either gratis or for a Distributor Fee, provided that you duplicate 79 | all of the original copyright notices and associated disclaimers. At 80 | your discretion, such verbatim copies may or may not include a 81 | Compiled form of the Package. 82 | 83 | (3) You may apply any bug fixes, portability changes, and other 84 | modifications made available from the Copyright Holder. The resulting 85 | Package will still be considered the Standard Version, and as such 86 | will be subject to the Original License. 87 | 88 | 89 | Distribution of Modified Versions of the Package as Source 90 | 91 | (4) You may Distribute your Modified Version as Source (either gratis 92 | or for a Distributor Fee, and with or without a Compiled form of the 93 | Modified Version) provided that you clearly document how it differs 94 | from the Standard Version, including, but not limited to, documenting 95 | any non-standard features, executables, or modules, and provided that 96 | you do at least ONE of the following: 97 | 98 | (a) make the Modified Version available to the Copyright Holder 99 | of the Standard Version, under the Original License, so that the 100 | Copyright Holder may include your modifications in the Standard 101 | Version. 102 | 103 | (b) ensure that installation of your Modified Version does not 104 | prevent the user installing or running the Standard Version. In 105 | addition, the Modified Version must bear a name that is different 106 | from the name of the Standard Version. 107 | 108 | (c) allow anyone who receives a copy of the Modified Version to 109 | make the Source form of the Modified Version available to others 110 | under 111 | 112 | (i) the Original License or 113 | 114 | (ii) a license that permits the licensee to freely copy, 115 | modify and redistribute the Modified Version using the same 116 | licensing terms that apply to the copy that the licensee 117 | received, and requires that the Source form of the Modified 118 | Version, and of any works derived from it, be made freely 119 | available in that license fees are prohibited but Distributor 120 | Fees are allowed. 121 | 122 | 123 | Distribution of Compiled Forms of the Standard Version 124 | or Modified Versions without the Source 125 | 126 | (5) You may Distribute Compiled forms of the Standard Version without 127 | the Source, provided that you include complete instructions on how to 128 | get the Source of the Standard Version. Such instructions must be 129 | valid at the time of your distribution. If these instructions, at any 130 | time while you are carrying out such distribution, become invalid, you 131 | must provide new instructions on demand or cease further distribution. 132 | If you provide valid instructions or cease distribution within thirty 133 | days after you become aware that the instructions are invalid, then 134 | you do not forfeit any of your rights under this license. 135 | 136 | (6) You may Distribute a Modified Version in Compiled form without 137 | the Source, provided that you comply with Section 4 with respect to 138 | the Source of the Modified Version. 139 | 140 | 141 | Aggregating or Linking the Package 142 | 143 | (7) You may aggregate the Package (either the Standard Version or 144 | Modified Version) with other packages and Distribute the resulting 145 | aggregation provided that you do not charge a licensing fee for the 146 | Package. Distributor Fees are permitted, and licensing fees for other 147 | components in the aggregation are permitted. The terms of this license 148 | apply to the use and Distribution of the Standard or Modified Versions 149 | as included in the aggregation. 150 | 151 | (8) You are permitted to link Modified and Standard Versions with 152 | other works, to embed the Package in a larger work of your own, or to 153 | build stand-alone binary or bytecode versions of applications that 154 | include the Package, and Distribute the result without restriction, 155 | provided the result does not expose a direct interface to the Package. 156 | 157 | 158 | Items That are Not Considered Part of a Modified Version 159 | 160 | (9) Works (including, but not limited to, modules and scripts) that 161 | merely extend or make use of the Package, do not, by themselves, cause 162 | the Package to be a Modified Version. In addition, such works are not 163 | considered parts of the Package itself, and are not subject to the 164 | terms of this license. 165 | 166 | 167 | General Provisions 168 | 169 | (10) Any use, modification, and distribution of the Standard or 170 | Modified Versions is governed by this Artistic License. By using, 171 | modifying or distributing the Package, you accept this license. Do not 172 | use, modify, or distribute the Package, if you do not accept this 173 | license. 174 | 175 | (11) If your Modified Version has been derived from a Modified 176 | Version made by someone other than you, you are nevertheless required 177 | to ensure that your Modified Version complies with the requirements of 178 | this license. 179 | 180 | (12) This license does not grant you the right to use any trademark, 181 | service mark, tradename, or logo of the Copyright Holder. 182 | 183 | (13) This license includes the non-exclusive, worldwide, 184 | free-of-charge patent license to make, have made, use, offer to sell, 185 | sell, import and otherwise transfer the Package with respect to any 186 | patent claims licensable by the Copyright Holder that are necessarily 187 | infringed by the Package. If you institute patent litigation 188 | (including a cross-claim or counterclaim) against any party alleging 189 | that the Package constitutes direct or contributory patent 190 | infringement, then this Artistic License to you shall terminate on the 191 | date that such litigation is filed. 192 | 193 | (14) Disclaimer of Warranty: 194 | THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS 195 | IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED 196 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 197 | NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL 198 | LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL 199 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 200 | DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF 201 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIDI-Perl HOWTO 2 | 3 | How to create algorithmic musical compositions with Perl! 4 | 5 | git clone https://github.com/ology/MIDI-Perl-HOWTO.git 6 | cd MIDI-Perl-HOWTO 7 | cpanm --installdeps . 8 | 9 | Please visit the [wiki](https://github.com/ology/MIDI-Perl-HOWTO/wiki) for the tutorial. 10 | 11 | ![](https://raw.githubusercontent.com/wiki/ology/MIDI-Perl-HOWTO/piano-camel.png?raw=true) 12 | -------------------------------------------------------------------------------- /cpanfile: -------------------------------------------------------------------------------- 1 | requires 'Data::Dumper::Compact'; 2 | requires 'MIDI::Drummer::Tiny'; 3 | requires 'MIDI::Simple'; 4 | requires 'MIDI::Util', '>= 0.0900'; 5 | requires 'Music::Chord::Note', '>= 0.10'; 6 | requires 'Music::Chord::Positions'; 7 | requires 'Music::Chord::Progression'; 8 | requires 'Music::Duration'; 9 | requires 'Music::Duration::Partition'; 10 | requires 'Music::MelodicDevice::Inversion'; 11 | requires 'Music::Note'; 12 | requires 'Music::Scales'; 13 | requires 'Music::ToRoman', '>= 0.1900'; 14 | requires 'Music::VoiceGen'; 15 | -------------------------------------------------------------------------------- /ex-01-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | print "Hello world!\n"; 6 | -------------------------------------------------------------------------------- /ex-01-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | 7 | my $data = { 8 | abc => 123, 9 | xyz => ['a', 42], 10 | }; 11 | 12 | print ddc($data); 13 | -------------------------------------------------------------------------------- /ex-01-03.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | use MIDI::Util qw(setup_score); 7 | 8 | my $score = setup_score(); 9 | 10 | print ddc($score); 11 | -------------------------------------------------------------------------------- /ex-01-04.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact qw(ddc); 6 | use MIDI::Util qw(setup_score); 7 | 8 | my $score = setup_score(); 9 | 10 | for my $note (qw(C4 D4 E4 F4)) { 11 | $score->n('qn', $note); 12 | $score->r('qn'); 13 | } 14 | 15 | print ddc($score); 16 | 17 | $score->write_score("$0.mid"); 18 | -------------------------------------------------------------------------------- /ex-02-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score); 6 | 7 | my $score = setup_score(); 8 | 9 | $score->synch(\&bass, \&treble); 10 | 11 | $score->write_score("$0.mid"); 12 | 13 | sub bass { 14 | for my $note (qw(C3 F3 G3 C4)) { 15 | $score->n('hn', $note); 16 | } 17 | } 18 | 19 | sub treble { 20 | for my $note (qw(C4 D4 E4 F4)) { 21 | $score->n('qn', $note); 22 | $score->r('qn'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ex-02-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score); 6 | 7 | my $score = setup_score(); 8 | 9 | $score->synch( 10 | sub { bass($score) }, 11 | sub { treble($score) }, 12 | ) for 1 .. 2; 13 | 14 | $score->write_score("$0.mid"); 15 | 16 | sub bass { 17 | my ($score) = @_; 18 | for my $note (qw(C3 F3 G3 C4)) { 19 | $score->n('hn', $note); 20 | } 21 | } 22 | 23 | sub treble { 24 | my ($score) = @_; 25 | for my $note (qw(C4 D4 E4 F4)) { 26 | $score->n('qn', $note); 27 | $score->r('qn'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ex-03-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score set_chan_patch); 6 | 7 | my $score = setup_score(); 8 | 9 | $score->synch(\&bass, \&treble); 10 | 11 | $score->write_score("$0.mid"); 12 | 13 | sub bass { 14 | set_chan_patch($score, 0, 35); 15 | for my $note (qw(C3 F3 G3 C4)) { 16 | $score->n('hn', $note, 'v127'); 17 | } 18 | } 19 | 20 | sub treble { 21 | set_chan_patch($score, 1, 0); 22 | for my $note (qw(C4 D4 E4 F4)) { 23 | $score->n('qn', $note, 'v120'); 24 | $score->r('qn'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ex-03-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score set_chan_patch); 6 | 7 | my $bpm = shift || 120; 8 | 9 | my $score = setup_score(bpm => $bpm); 10 | 11 | $score->synch(\&bass, \&treble); 12 | 13 | $score->write_score("$0.mid"); 14 | 15 | sub bass { 16 | set_chan_patch($score, 0, 35); 17 | for my $note (qw(C3 F3 G3 C4)) { 18 | $score->n('hn', $note); 19 | } 20 | } 21 | 22 | sub treble { 23 | set_chan_patch($score, 1, 0); 24 | for my $note (qw(C4 D4 E4 F4)) { 25 | $score->n('qn', $note); 26 | $score->r('qn'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ex-04-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score set_chan_patch); 6 | 7 | my $score = setup_score(bpm => 120, volume => 120); 8 | 9 | $score->synch(\&bass, \&treble); 10 | 11 | $score->write_score("$0.mid"); 12 | 13 | sub bass { 14 | set_chan_patch($score, 0, 35); 15 | for my $note (qw(C3 F3 G3 C4)) { 16 | $score->n('hn', $note); 17 | } 18 | } 19 | 20 | sub treble { 21 | set_chan_patch($score, 1, 0); 22 | 23 | my @pitches = (60, 62, 64, 65, 67, 69, 71, 72); 24 | 25 | for my $n (1 .. 4) { 26 | my $pitch = $pitches[int rand @pitches]; 27 | $score->n('qn', $pitch); 28 | $score->r('qn'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ex-04-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score set_chan_patch); 6 | use Music::Scales qw(get_scale_MIDI); 7 | 8 | my $score = setup_score(bpm => 120, volume => 120); 9 | 10 | $score->synch(\&bass, \&treble); 11 | 12 | $score->write_score("$0.mid"); 13 | 14 | sub bass { 15 | set_chan_patch($score, 0, 35); 16 | 17 | my @pitches = get_scale_MIDI('C', 2, 'pentatonic'); 18 | 19 | for my $n (1 .. 4) { 20 | my $pitch = $pitches[int rand @pitches]; 21 | $score->n('hn', $pitch); 22 | } 23 | } 24 | 25 | sub treble { 26 | set_chan_patch($score, 1, 0); 27 | 28 | my @pitches = get_scale_MIDI('C', 4, 'major'); 29 | 30 | for my $n (1 .. 4) { 31 | my $pitch = $pitches[int rand @pitches]; 32 | $score->n('qn', $pitch); 33 | $score->r('qn'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ex-04-03.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score set_chan_patch); 6 | use Music::Scales qw(get_scale_MIDI); 7 | 8 | my $score = setup_score(bpm => 120, volume => 120); 9 | 10 | $score->synch( 11 | \&bass, 12 | \&treble, 13 | ) for 1 .. 4; 14 | 15 | $score->write_score("$0.mid"); 16 | 17 | sub bass { 18 | set_chan_patch($score, 0, 35); 19 | 20 | my @pitches = ( 21 | get_scale_MIDI('C', 2, 'pentatonic'), 22 | # get_scale_MIDI('C', 3, 'pentatonic'), 23 | ); 24 | 25 | for my $n (1 .. 4) { 26 | my $pitch = $pitches[int rand @pitches]; 27 | $score->n('hn', $pitch); 28 | } 29 | } 30 | 31 | sub treble { 32 | set_chan_patch($score, 1, 0); 33 | 34 | my @pitches = ( 35 | get_scale_MIDI('C', 4, 'major'), 36 | get_scale_MIDI('C', 5, 'major'), 37 | ); 38 | 39 | for my $n (1 .. 4) { 40 | my $pitch = $pitches[int rand @pitches]; 41 | $score->n('qn', $pitch); 42 | $score->r('qn'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ex-04-04.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Music::Note; 6 | 7 | my $note = Music::Note->new('C4', 'ISO'); 8 | print $note->format('midinum'), "\n"; 9 | 10 | $note = Music::Note->new(60, 'midinum'); 11 | print $note->format('ISO'), "\n"; 12 | -------------------------------------------------------------------------------- /ex-05-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | #use MIDI::Simple; 7 | use Music::Duration; 8 | 9 | my %x = %MIDI::Simple::Length; 10 | 11 | print ddc([ map { "$_ => $x{$_}" } sort { $x{$a} <=> $x{$b} } keys %x ]); 12 | -------------------------------------------------------------------------------- /ex-05-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | use Music::Duration::Partition; 7 | 8 | my $mdp = Music::Duration::Partition->new( 9 | size => 4, 10 | pool => [qw(hn dqn qn en)], 11 | ); 12 | 13 | for my $i (1 .. 8) { 14 | my $motif = $mdp->motif; 15 | print ddc($motif); 16 | } 17 | -------------------------------------------------------------------------------- /ex-06-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | 7 | use MIDI::Drummer::Tiny; 8 | 9 | my $d = MIDI::Drummer::Tiny->new; 10 | 11 | print ddc($d); 12 | -------------------------------------------------------------------------------- /ex-06-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Drummer::Tiny; 6 | 7 | my $d = MIDI::Drummer::Tiny->new; 8 | 9 | $d->count_in(4); # Closed hi-hat for 4 bars 10 | 11 | $d->write; 12 | -------------------------------------------------------------------------------- /ex-06-03.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Drummer::Tiny; 6 | 7 | my $d = MIDI::Drummer::Tiny->new(bars => 8); 8 | 9 | $d->metronome44; # 4/4 time for the number of bars 10 | 11 | $d->write; 12 | -------------------------------------------------------------------------------- /ex-07-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact qw(ddc); 6 | use Music::Scales qw(get_scale_MIDI); 7 | use Music::VoiceGen; 8 | 9 | my @pitches = ( 10 | get_scale_MIDI('C', 4, 'minor'), 11 | get_scale_MIDI('C', 5, 'minor'), 12 | ); 13 | 14 | my $voice = Music::VoiceGen->new( 15 | pitches => \@pitches, 16 | intervals => [qw(-4 -3 -2 -1 1 2 3 4)], 17 | ); 18 | 19 | my @notes = map { $voice->rand } 1 .. 8; 20 | 21 | print ddc(\@notes); 22 | -------------------------------------------------------------------------------- /ex-08-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | use MIDI::Util qw(setup_score); 7 | use Music::Scales qw(get_scale_MIDI); 8 | 9 | my @pitches = ( 10 | get_scale_MIDI('C', 4, 'minor'), 11 | get_scale_MIDI('C', 5, 'minor'), 12 | ); 13 | 14 | my $score = setup_score(); 15 | 16 | for my $i (1 .. 8) { 17 | my @chord = map { $pitches[int rand @pitches] } 1 .. 3; 18 | print ddc(\@chord); 19 | $score->n('wn', @chord); 20 | } 21 | 22 | $score->write_score("$0.mid"); 23 | -------------------------------------------------------------------------------- /ex-08-02.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | use MIDI::Util qw(setup_score midi_format); 7 | use Music::Chord::Note; 8 | 9 | my $score = setup_score(); 10 | 11 | my $mcn = Music::Chord::Note->new; 12 | 13 | for my $c (qw(Cm7 F7 BbM7 EbM7 Adim7 D7 Gm)) { 14 | my @chord = $mcn->chord_with_octave($c, 4); 15 | 16 | @chord = midi_format(@chord); 17 | print ddc(\@chord); 18 | 19 | $score->n('wn', @chord); 20 | } 21 | 22 | $score->write_score("$0.mid"); 23 | -------------------------------------------------------------------------------- /ex-08-03.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score); 6 | use Music::Scales qw(get_scale_MIDI); 7 | 8 | my @pitches = ( 9 | get_scale_MIDI('C', 3, 'major'), 10 | get_scale_MIDI('C', 4, 'major'), 11 | ); 12 | 13 | my $score = setup_score(); 14 | 15 | $score->synch( 16 | sub { dyads($score, \@pitches) }, 17 | sub { single_note($score, \@pitches) }, 18 | ); 19 | 20 | $score->write_score("$0.mid"); 21 | 22 | sub single_note { 23 | my ($s, $pitches) = @_; 24 | for my $i (1 .. 8) { 25 | for my $n (1 .. 4) { 26 | my $pitch = $pitches->[rand int @$pitches]; 27 | $s->n('qn', $pitch); 28 | } 29 | } 30 | } 31 | 32 | sub dyads { 33 | my ($s, $pitches) = @_; 34 | for my $i (1 .. 8) { 35 | my $pitch = $pitches->[rand int @$pitches]; 36 | $s->n('wn', $pitch, $pitch + 7); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ex-08-04.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | use Music::Chord::Positions; 7 | use Music::Note; 8 | 9 | my $mcp = Music::Chord::Positions->new; 10 | 11 | my $inversion = shift || 1; # Or 2 12 | 13 | # Define the initial chord 14 | my @chord = qw(C4 E4 G4); 15 | print 'Chord: ', ddc(\@chord); 16 | 17 | # Get the list of octaves for each note 18 | my @octaves = map { s/[A-G][#b]?//r } @chord; 19 | print 'Octaves: ', ddc(\@octaves); 20 | 21 | # Get the list of note names without octaves 22 | my @isobase = map { s/\d+//r } @chord; 23 | print 'ISObase: ', ddc(\@isobase); 24 | 25 | # Get the pitch class 26 | my @pitches = map { Music::Note->new($_ . -1, 'ISO')->format('midinum') } @isobase; 27 | print 'Pitches: ', ddc(\@pitches); 28 | 29 | # Invert the pitches 30 | my $inverted = $mcp->chord_inv(\@pitches, inv_num => $inversion); 31 | print 'Inverted: ', ddc($inverted); 32 | 33 | # Convert the inverted pitches back to named notes 34 | my @notes = map { Music::Note->new($_, 'midinum')->format('ISO') } @$inverted; 35 | print 'New: ', ddc(\@notes); 36 | 37 | # Clean-up the new chord notes 38 | for my $i (0 .. $#notes) { 39 | $notes[$i] =~ s/-1/$octaves[$i]/; 40 | $notes[$i] =~ s/0/$octaves[$i] + 1/e; 41 | } 42 | print 'Fixed: ', ddc(\@notes); 43 | -------------------------------------------------------------------------------- /ex-08-05.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use Data::Dumper::Compact 'ddc'; 6 | use MIDI::Util qw(setup_score); 7 | use Music::Chord::Progression; 8 | 9 | # Create a chord progression generator 10 | my $prog = Music::Chord::Progression->new; 11 | 12 | my $chords = $prog->generate; 13 | print ddc($chords); 14 | 15 | my $score = setup_score(); 16 | 17 | # Add the notes to the score 18 | $score->n('wn', @$_) for @$chords; 19 | 20 | $score->write_score("$0.mid"); 21 | -------------------------------------------------------------------------------- /ex-09-01.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | 5 | use MIDI::Util qw(setup_score); 6 | use Music::Scales qw(get_scale_MIDI); 7 | use Music::VoiceGen; 8 | 9 | my @pitches = ( 10 | get_scale_MIDI('C', 3, 'major'), 11 | get_scale_MIDI('C', 4, 'major'), 12 | ); 13 | 14 | my $voice = Music::VoiceGen->new( 15 | pitches => \@pitches, 16 | intervals => [qw(-4 -3 -2 -1 1 2 3 4)], 17 | ); 18 | 19 | my $score = setup_score(bpm => 120); 20 | 21 | for my $i (1 .. 8) { 22 | for my $n (1 .. 4) { 23 | my $pitch = $voice->rand; 24 | 25 | # Get a fluctuating volume between f and fff 26 | my $vol = 'v' . (96 + int(rand 32)); 27 | 28 | if ($i % 2 == 0) { 29 | $score->n('qn', $pitch, $vol); 30 | $score->r('qn'); 31 | } 32 | else { 33 | $score->n('hn', $pitch, $vol); 34 | } 35 | } 36 | } 37 | 38 | $score->write_score("$0.mid"); 39 | --------------------------------------------------------------------------------