Skip to content

Commit 4dd895b

Browse files
committed
some new words in lib/midi.dc; and a microtonal riff example
1 parent 3b4fe0c commit 4dd895b

File tree

3 files changed

+167
-7
lines changed

3 files changed

+167
-7
lines changed

examples/edo_riff.dc

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"midi.dc" import
2+
3+
17 midi_edo !
4+
5+
: generate_interval
6+
/ log2 midi_edo @ * round
7+
;
8+
9+
9 8 generate_interval const STEP
10+
6 5 generate_interval const MIN3
11+
6 5 generate_interval const THIRD
12+
3 2 generate_interval const FIFTH
13+
9 5 generate_interval const SEV
14+
15+
create choices 0 , STEP , THIRD , FIFTH , SEV ,
16+
create lengths 0.25 , 0.25 ,
17+
create attacks 96 , 32 , 32 , 32 , 32 ,
18+
create modulations FIFTH , MIN3 , FIFTH , MIN3 ,
19+
var stopgap
20+
lengths choices - const CHOICES_SIZE
21+
CHOICES_SIZE 2 * const MEASURE
22+
stopgap modulations - const MODUSIZE
23+
var step
24+
0 step !
25+
var modulations_pointer
26+
0 modulations_pointer !
27+
28+
: _advance_step
29+
step @ 1 + step !
30+
;
31+
32+
: _get_modulations_pointer
33+
modulations_pointer @ dup
34+
MODUSIZE =
35+
if
36+
drop
37+
0
38+
endif
39+
dup 1 + modulations_pointer !
40+
;
41+
42+
: _add_interval
43+
svpush
44+
CHOICES_SIZE times
45+
choices i + @
46+
0 svpick + # interval on stack is added here
47+
midi_edo @ %
48+
choices i + !
49+
again
50+
svdrop
51+
# lower first note (root) an octave
52+
choices @ midi_edo @ -
53+
choices !
54+
choices CHOICES_SIZE sortnums
55+
;
56+
57+
: _do_transposition
58+
step @ MEASURE %
59+
0 =
60+
if
61+
modulations
62+
_get_modulations_pointer
63+
+ @
64+
_add_interval
65+
endif
66+
;
67+
68+
: _get_edo_note
69+
step @
70+
CHOICES_SIZE %
71+
choices + @
72+
step @
73+
CHOICES_SIZE %
74+
attacks + @
75+
;
76+
77+
: _get_length
78+
rand 2 * round 2 %
79+
lengths + @
80+
;
81+
82+
: edo_riff
83+
block_sigint
84+
_get_edo_note
85+
# stack: ( note attack ) ( )
86+
over 0 edo_degree_to_midi
87+
_get_length sleep
88+
0 swap 0 edo_degree_to_midi
89+
0.01 sleep
90+
unblock_sigint
91+
_advance_step
92+
_do_transposition
93+
edo_riff
94+
;
95+
96+
edo_riff
97+
98+
8192 0 0xE0 send_midi_reverse

examples/midi_change_ring.dc

+11-7
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@ var fpnt
77
"change_ring.txt" "r" fopen fpnt !
88

99
create pentatonic 50 , 52 , 55 , 57 , 60 ,
10-
create lengths 2 , 1 , 2 , 2 , 1 ,
10+
create lengths 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
11+
create vols 96 , 96 , 96 , 96 , 96 , 0 , 0 , 0 ,
12+
5 const CYCLE_SIZE
1113
var length_idx
12-
0.16 const BASE_LEN
13-
BASE_LEN 0.97 * const ON_LEN
14-
BASE_LEN ON_LEN - const OFF_LEN
14+
0.152 const BASE_LEN
15+
BASE_LEN 0.95 * const ON_LEN
16+
BASE_LEN 0.05 * const OFF_LEN
1517
6 const TRANSPOSE
1618

1719
: length_idx++ length_idx dup @ 1 + swap ! ;
1820

19-
: _get_on_length lengths length_idx @ 5 % + @ ON_LEN * ;
21+
: _get_on_length lengths length_idx @ CYCLE_SIZE % + @ ON_LEN * ;
2022

21-
: _get_off_length lengths length_idx @ 5 % + @ OFF_LEN * ;
23+
: _get_off_length lengths length_idx @ CYCLE_SIZE % + @ OFF_LEN * ;
24+
25+
: _get_vol vols length_idx @ CYCLE_SIZE % + @ ;
2226

2327
: _get_next
2428
strsav lnpnt fpnt
@@ -47,7 +51,7 @@ BASE_LEN ON_LEN - const OFF_LEN
4751
TRANSPOSE
4852
+
4953
dup svpush
50-
96
54+
_get_vol
5155
send_midi
5256
###
5357
_get_on_length sleep

lib/midi.dc

+58
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var mididev
55
var inbuf
66
var direction
77
var midi_ctl_slots 128 allot
8+
var midi_channel_last_note 16 allot
89

910
: setup_port
1011
"DCLANG_MIDI_PORT_DIRECTION"
@@ -85,6 +86,17 @@ setup_port
8586
resetout
8687
;
8788

89+
: send_midi_reverse
90+
# sometimes, it's easier to have the stack be queued out such
91+
# the the top-of-stack goes out first. So, in this case, one would
92+
# for example put the volumn, then the note, then the status_byte
93+
# on the stack in that order. Then it's a simple matter of emitting
94+
# three times with zero stack-dancing or svpush or swapping involved.
95+
get_mididev redirect
96+
emit emit emit
97+
flush resetout
98+
;
99+
88100
: panic
89101
get_mididev
90102
redirect
@@ -97,3 +109,49 @@ setup_port
97109
next
98110
resetout
99111
;
112+
113+
# words for microtonal/alternate tuning musical applications
114+
115+
: _bend_to_MSB_LSB_bytes
116+
# a helper function. Given a top-of-stack 14-byte integer MIDI
117+
# pitch-bend amount, replace the top-of-stack with two bytes,
118+
# the top-of-stack being the LSB (least significant byte) and the next
119+
# being the most significant byte
120+
dup 7 >>
121+
swap 0x7f and
122+
;
123+
124+
125+
# Set the default variable 'midi_edo' to 31. Can be changed by the user later...
126+
var midi_edo
127+
31 midi_edo !
128+
129+
: edo_degree_to_midi
130+
# input stack (rightmost is "top":
131+
# ( volume, edo_degree, midi_channel )
132+
#
133+
# Take an input edo degree, calculate the octave fraction against the global
134+
# EDO constant, which must be declared ahead-of-time, and emit midi bytes
135+
# to the configured MIDI output device which will sound the correct pitch
136+
# Middle-C is assumed to be "0" in all EDOs, so use negative numbers to go
137+
# below middle-C.
138+
svpush # sequester the channel number away
139+
midi_edo @ / 12 * # scale to 12-EDO with fractional remainder
140+
60.5 + # shift to middle-C in MIDI, also overshoot fractional
141+
dup floor swap # part on purpose so we can fetch the floor closest
142+
# to the proper midi number; set aside by swap
143+
over - 0.5 - # grab fractional part and cancel previous 0.5 shift
144+
4096 * # scale by positive half step of bend
145+
8192 + # center zero at halfway for +/-
146+
# stack now looks like:
147+
# ( volume midi_note_number midi_bend ) ( midi_channel )
148+
_bend_to_MSB_LSB_bytes
149+
# now we have
150+
# ( volume midi_note_number bend_MSB bend_LSB ) ( midi_channel )
151+
# send the bend
152+
0 svpick 0xE0 +
153+
send_midi_reverse
154+
# send the note
155+
svpop 0x90 +
156+
send_midi_reverse
157+
;

0 commit comments

Comments
 (0)