Skip to content

Commit e7afcd3

Browse files
committed
fixes: arp, script, started: test synth, tutorial
1 parent 92e9403 commit e7afcd3

File tree

11 files changed

+371
-98
lines changed

11 files changed

+371
-98
lines changed

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[MESSAGES CONTROL]
2-
disable=C0326,C0303
2+
disable=C0326,C0303,R1714

README.md

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ Textbeat is a new project, but you can already do lots of cool things:
2929
- Strumming
3030
- Arpeggiation
3131
- Tuplets and polyrhythms
32-
- CC automation
33-
- Vibrato, pitch, and mod wheels
32+
- MIDI CC automation
33+
- Vibrato, pitch, and mod wheel control
3434
- Dynamics
3535
- Accents
3636
- Velocity
@@ -46,6 +46,8 @@ Textbeat is a new project, but you can already do lots of cool things:
4646
You can use the shell with General Midi out-of-the-box on windows, which is great for learning,
4747
but sounds bad without a decent soundfont.
4848

49+
I'm currently working on headless VST rack generation.
50+
4951
If you want to use VST instruments, you'll need to route the MIDI out to something that hosts them, like a DAW.
5052

5153
For windows, you can use a virtual midi driver, such as [loopMIDI](http://www.tobias-erichsen.de/software/loopmidi.html) for usage with a VST host or DAW.
@@ -321,9 +323,9 @@ Unlike accents, volume changes persist.
321323

322324
Interpolation is not yet impl
323325

324-
## Articulation
326+
## Vibrato, Pitch, and Mod Wheel
325327

326-
The vibrato symbol is a tilda (~).
328+
To add vibrato to a note, suffix it with a tilda (~).
327329

328330
Vibrato uses the mod wheel right now, but will eventually use pitch wheel oscillation.
329331

@@ -332,7 +334,7 @@ In the future, articulation will be programmable, per-track or per-song.
332334
## Arpeggio Modulation
333335

334336
Notes of arpeggios can be modified as they're running,
335-
by having effects in a grid space, for example:
337+
by having effects in the grid space they occur, for example:
336338

337339
```
338340
maj7&
@@ -347,7 +349,7 @@ maj7&
347349

348350
maj7& starts a repeating 4-note arpeggio, and we indent to show this.
349351

350-
Certain notes of the sequence are modulated with short/staccato '.', soft '?' and accent '!'
352+
Certain notes of the sequence are modulated with short/staccato '.', soft '?', and accent '!'
351353

352354
For staccato usage w/o a note name, an extra dot is required since '.' is simply a placeholder.
353355

@@ -367,7 +369,7 @@ The dots are placeholders.
367369
. 1''
368370
```
369371

370-
Columns can be detected in some cases, but you'll probably want to
372+
Columns can be detected (in some cases), but you'll probably want to
371373
specify the column width manually at the top,
372374
which allows vim to mark the columns.
373375

@@ -386,7 +388,8 @@ For best view in an editor, it is recommended that you offset the first column b
386388
## Patches
387389

388390
Another useful global var is 'p', which sets midi patches by name or number
389-
across the tracks. The midi names support partial case-insensitive matches.
391+
across the tracks. The midi names support both patch numbers and partial case-insensitive
392+
matches of GM instruments.
390393

391394
```
392395
%t120 x2 p=piano,guitar,bass,drums c8,-2
@@ -396,17 +399,18 @@ For a full list of GM names, see [def/gm.yaml](https://github.com/flipcoder/text
396399

397400
## Tuplets
398401

399-
Very early support for this. See tuplet example.
400-
The 't' command spreads a set of notes across a tuplet grid,
401-
starting at the first occurence of t in that group.
402+
The 'T' (tuplet) gives us access to the musical concept of tuplets (called triplets in cases of 3).
403+
which allows note timing and durations to fall along a ratio instead of the usual note subdivisions.
404+
405+
Tuplets are marked by 'T' and have an optional value at the first occurence in that group.
402406
Ratios provided will control expansion. Default is 3:4.
403407
If no denominator is given, it will default to the next power of two
404408
(so 3:4, 5:8, 7:8, 11:16).
405-
So in other words if you need a 5:6, you'll need to write t5:6. :)
406-
The ratio of the beat saves. You only need to specify it once per group.
409+
So in other words, T5 is the same as T5:8, but if you need a 5:6, you'll need to write T5:6.
410+
The ratio of the tuplet persists for the rest of the grouping.
407411
For nested tripets, group those by adding an extra 'T'.
408412

409-
Consider the 2 tracks:
413+
The two tracks below are a basic usage of triplets:
410414

411415
```
412416
1 1T
@@ -419,8 +423,14 @@ Consider the 2 tracks:
419423
4
420424
```
421425

422-
The spacing is not even between the sets, but the 'T' value stretches them
423-
to make them line up in a default ratio of 3:4.
426+
The first column is playing notes along the grid normally, while the
427+
2nd column is playing 3 notes in the space of the others' 4 notes.
428+
429+
Even though there is visual spacing between the triplet groups, the 'T' value effective
430+
stretches the notes so they occur along a slower grid according to that ratio.
431+
432+
The spaces that occur after (and between) tuplet groupings should remain empty,
433+
since they are spacers to make the expansion line up.
424434

425435
## Picking
426436

@@ -435,7 +445,7 @@ to make them line up in a default ratio of 3:4.
435445
# to set a relative key, this will go from a major scale to relative minor scale
436446
%k+6
437447
438-
# you can also go down to relative minor below
448+
# you can also go downwards
439449
%k-6
440450
441451
# scale names are supported, this changes the scale shape to dorian
@@ -447,10 +457,10 @@ to make them line up in a default ratio of 3:4.
447457

448458
## Chords (Advanced)
449459

450-
Slash chords do not imply inversions,
451-
but are for stacking across octaves. Additionally, note names alone do no imply chords.
460+
In textbeat, slash (/) chords do not imply inversions,
461+
but are for spanning chord voicings across octaves. Additionally, note names alone do no imply chords.
452462
For example, C/E means play a C note with an E in a lower octave, whereas a musician might
453-
interpret this as a specific chord voicing. (Inversions use shift operator (maj> for first inversion))
463+
interpret this as a specific chord voicing. Inversions in textbeat uses shift operator (>) instead (maj> for maj first inversion))
454464

455465
```
456466
b7maj7#4/sus2/1
@@ -468,7 +478,7 @@ Check out the examples/ folder. Play them with textbeat from the
468478
command line:
469479

470480
```
471-
./textbeat.py examples/jazz
481+
./txbt examples/jazz.txbt
472482
```
473483

474484
# Advanced
@@ -635,7 +645,7 @@ Example: 1~ is fine, but 1v is not. Use 1@v You only need one to combine: 1@v5e5
635645
Note: Fractional values specified are formated like numbers after a decimal point:
636646
Example: 3, 30, and 300 all mean 30% (read like .3, .30, etc.)
637647
638-
CC mapping is customizable inside [def/cc.yaml](https://github.com/flipcoder/textbeat/blob/master/def/default.yaml).
648+
CC mapping is customizable inside [def/cc.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/default.yaml).
639649
640650
```
641651

@@ -659,9 +669,9 @@ CC mapping is customizable inside [def/cc.yaml](https://github.com/flipcoder/tex
659669

660670
A majority of the music index is contained in inside these files:
661671

662-
- Default: [def/default.yaml](https://github.com/flipcoder/textbeat/blob/master/def/default.yaml).
663-
- Informal: [def/informal.yaml](https://github.com/flipcoder/textbeat/blob/master/def/informal.yaml).
664-
- Experimental: [def/exp.yaml](https://github.com/flipcoder/textbeat/blob/master/def/exp.yaml).
672+
- Default: [def/default.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeatdef/default.yaml).
673+
- Informal: [def/informal.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/informal.yaml).
674+
- Experimental: [def/exp.yaml](https://github.com/flipcoder/textbeat/blob/master/textbeat/def/exp.yaml).
665675

666676
These lists does not include certain chord modifications (add, no, drop, etc.).
667677

examples/drums1.txbt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
%t120 x2 c20,-2 p=drums f=loop
2+
1
3+
b5$?
4+
b5?
5+
3
6+
b5$?
7+
b5?

setup.py

100755100644
File mode changed.

textbeat/__main__.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@
44
Open-source under MIT License
55
66
Examples:
7-
textbeat.py shell
8-
textbeat.py song.txbt play song
7+
textbeat shell
8+
textbeat song.txbt play song
99
1010
Usage:
11-
textbeat.py [--dev=<device> | --verbose | --midi=<fn> | --ring | --follow | --loop] [-eftnpsrxhv] [SONGNAME]
12-
textbeat.py [+RANGE] [--dev=<device> | --midi=<fn> | --ring | --follow | --loop] [-eftnpsrxhv] [SONGNAME]
13-
textbeat.py -c [COMMANDS ...]
14-
textbeat.py -l [LINE_CONTENT ...]
11+
textbeat [--dev=<device> | --midi=<fn> | --ring | --follow --stdin] [-aeftnpsrxhvL] [SONGNAME]
12+
textbeat [+RANGE] [--dev=<device> | --midi=<fn> | --ring | --follow | --stdin] [-aeftnpsrxhvL] [SONGNAME]
13+
textbeat -c [COMMANDS ...]
14+
textbeat -l [LINE_CONTENT ...]
1515
1616
Options:
1717
-h --help show this
1818
-v --verbose verbose
19+
-T --tutorial (STUB) tutorial
1920
-t --tempo=<bpm> (STUB) set tempo [default: 120]
2021
-x --grid=<g> (STUB) set grid [default: 4]
2122
-n --note=<n> (STUB) set grid using note value [default: 1]
@@ -25,9 +26,10 @@
2526
-f --flags comma-separated global flags
2627
-c execute commands sequentially
2728
-l execute commands simultaenously
29+
--stdin read from stdin instead of file
2830
-r --remote (STUB) remote/daemon mode, keep alive
2931
--ring don't mute midi on end
30-
--loop loop song
32+
-L --loop loop song
3133
--midi=<fn> generate midi file
3234
+<range> play from line or maker, for range use start:end
3335
-e --edit (STUB) open file in editor
@@ -41,7 +43,7 @@
4143
--lint (STUB) analyze file
4244
--follow (old) print newlines every line, no output
4345
--quiet no output
44-
--input (STUB) midi input chord analyzer
46+
-a --analyze (STUB) midi input chord analyzer
4547
"""
4648
from __future__ import absolute_import, unicode_literals, print_function, generators
4749
# try:
@@ -51,7 +53,7 @@
5153
def main():
5254
# if __name__!='__main__':
5355
# sys.exit(0)
54-
ARGS = docopt(__doc__)
56+
ARGS = docopt(__doc__.replace('TEXTBEAT',os.path.basename(sys.argv[0]).lower()))
5557
set_args(ARGS)
5658

5759
from . import support
@@ -110,11 +112,13 @@ def main():
110112
elif arg == '--edit': pass
111113
elif arg == '-l': player.cmdmode = 'l'
112114
elif arg == '-c': player.cmdmode = 'c'
115+
elif arg == '-T':
116+
player.tutorial = Tutorial(player)
113117
elif arg =='--flags':
114118
vals = val.split(',')
115119
player.add_flags(map(player.FLAGS.index, vals))
116120
elif arg == '--loop': player.add_flags(Player.Flag.LOOP)
117-
elif arg == '--renderman': player.renderman = True
121+
# elif arg == '--renderman': player.renderman = True
118122

119123
if player.cmdmode=='l':
120124
player.buf = ' '.join(ARGS['LINE_CONTENT']).split(';') # ;
@@ -123,8 +127,14 @@ def main():
123127
else: # mode n
124128
# if len(sys.argv)>=2:
125129
# FN = sys.argv[-1]
126-
if ARGS['SONGNAME']:
127-
FN = ARGS['SONGNAME']
130+
FN = ARGS['SONGNAME']
131+
from_stdin = False
132+
if FN=='-' or ARGS['--stdin']:
133+
FN = 0 # TEMP: doesnt work with py2
134+
from_stdin = True
135+
else:
136+
from_stdin = False
137+
if FN or from_stdin:
128138
# player.markers[''] = 0 # start marker
129139
with open(FN) as f:
130140
lc = 0
@@ -161,7 +171,7 @@ def main():
161171
player.cmdmode = ''
162172
player.shell = True
163173

164-
player.interactive = player.shell or player.remote
174+
player.interactive = player.shell or player.remote or player.tutorial
165175

166176
pygame.midi.init()
167177
if pygame.midi.get_count()==0:
@@ -258,28 +268,28 @@ def main():
258268
active = support.SUPPORT_ALL & support.SUPPORT
259269
inactive = support.SUPPORT_ALL - support.SUPPORT
260270
if active:
261-
log(FG.GREEN + 'Active Modules: ' + FG.WHITE + ', '.join(active) + FG.WHITE)
271+
log(FG.GREEN + 'Active Modules: ' + STYLE.RESET_ALL + ', '.join(active) + STYLE.RESET_ALL)
262272
if inactive:
263-
log(FG.RED + 'Inactive Modules: ' + FG.WHITE + ', '.join(inactive))
273+
log(FG.RED + 'Inactive Modules: ' + STYLE.RESET_ALL + ', '.join(inactive))
264274
if player.portname:
265-
log(FG.GREEN + 'Device: ' + FG.WHITE + '%s' % (player.portname if player.portname else 'Unknown',))
266-
log(FG.RED + 'Other Devices: ' + FG.WHITE + '%s' % (', '.join(portnames)))
275+
log(FG.GREEN + 'Device: ' + STYLE.RESET_ALL + '%s' % (player.portname if player.portname else 'Unknown',))
276+
log(FG.RED + 'Other Devices: ' + STYLE.RESET_ALL + '%s' % (', '.join(portnames)))
267277
if player.portname:
268278
if player.tracks[0].midich == DRUM_CHANNEL:
269279
log(FG.GREEN + 'GM Percussion')
270280
else:
271-
log(FG.GREEN + 'GM Patch: '+ FG.WHITE +'%s' % GM[player.tracks[0].patch_num])
281+
log(FG.GREEN + 'GM Patch: '+ STYLE.RESET_ALL +'%s' % GM[player.tracks[0].patch_num])
272282

273-
log('Use -h for command line options.')
274-
log('Read the manual and look at examples. Have fun!')
283+
# log('')
284+
# log(FG.BLUE + 'New? Type help and press enter to start the tutorial.')
275285
log('')
276286

277287
player.run()
278288

279289
if player.midifile:
280290
player.midifile.save(midifn)
281291

282-
# TODO: turn all midi note off
292+
# TODO: turn all midi note off
283293
i = 0
284294
for ch in player.tracks:
285295
if not player.ring:

0 commit comments

Comments
 (0)