summaryrefslogtreecommitdiff
path: root/support/pstab/PStab
blob: 74bf88c61978a318ac0a9d0f730b58272bc3dd1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
%!
%%Title:PStab 2.0
%%Creator:Baz
%%CreationDate:14 March 1994
%PStab 2.0 (first full release)
%
%
%   Copyright (C) 1994 Brian Ewins.  All rights reserved.
%
%PStab is distributed in the hope that it will be useful, but
%WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
%to anyone for the consequences of using it or for whether it serves any
%particular purpose or works at all, unless he says so in writing.  Refer
%to the PStab General Public License for full details.
%
%Everyone is granted permission to copy, modify and redistribute
%PStab, but only under the conditions described in the PStab
%General Public License.  A copy of this license is supposed to have been
%given to you along with PStab so you can know your rights and
%responsibilities.  It should be in a file named COPYING.  Among other
%things, the copyright notice and this notice must be preserved on all
%copies.
%
%-------------------------------------------------------------------------------
%Revision History: started Friday, 2 March 1994.
%-------------------------------------------------------------------------------
% 0.1 	:Friday: 	crap program for lining numbers up in columns
% 0.2 	:Sunday: 	complete rewrite. chord table program only
% 0.3 	:Tuesday:	reorganized into core & styles.
%			Centred,Columns,ChordTable supplied.
%			ifcase added to core.
% 0.4	:Wednesday: 	rethink on text styles.easier method of entry.
%			Verses replaced Columns
%			ChordPro style provides compatability.
%			ChordTable renamed Chords, now has
%			huge table of chords you can use.
%			Handles VM restore properly !!!
%			added revision history.
% 0.5	:Thursday:	Back to doing tablature (again)
%			Chords now size-independent
%			Verbatim made default style.
%			Verbatim-equivalent defs removed.(shortens prog}
%			Tablature works! hooray!!!
%			Many marks allowed in music.
% 0.6	:Friday:	added default case to ifcase
%			finished Parser. program is still buggy.
% 0.7	::		Due to a hitch, there was no alpha 7.
% 0.8	:Sunday:	Commented.
%			fbox made internal size.
%			Manual doubles as torture test.
%			manual nearly complete, program debugged
%			completely except for Tablature.
% 1.0	:Monday:	It all works!!! I'll type last man page & post.
% 1.1	:Tuesday:	the '2nd last page' bug fixed.
%			fingermark bug fixed. top , bottom, rows set
%			once only in Tablature.
%			Parsers now separate part of the program.
%			Font sizes reduced:I was viewing on A3!!!
%			Errors in manual fixed.
%			Only things left to do now are ASCII tab reader,
%			and more complete manual.
% 1.2:	:Tuesday:	ASCII parser started. buggy. remembered to fix bug
%			for looooong bars.incidentally, redundant defs were
%			placed back in at 1.0. ASCII parser works. WOW!
%			manual to do. ASCII parser now does an excellent
%			job of it. only two pathogenic cases I can think of.
% 2.0:	:Wednesday:	ASCII parser fixed so it split up 'bars'. this
%			is truly monumental: ASCII'd tab now looks
%			_nice_ (!)... almost worth using...
%			manual finished.
%-------------------------------------------------------------------------------
%-CORE--------------------------------------------------------------------------
%Contains idioms, and other stuff essential for
%the program to break lines, pages, etc.
%-------------------------------------------------------------------------------
%-------Idioms
%-------------------------------------------------------------------------------
/debug {dup 20 string cvs show ( ) show} def
/edef {exch def} def
/max { 2 copy gt {pop} {exch pop} ifelse } def
/min { 2 copy lt {pop} {exch pop} ifelse } def
/inch {72 mul} def
/plus
{ % x y plus is equivalent to x+=y; in C
	1 index cvx exec add def
} def
/minus
{ % x y minus is equivalent to x-=y; in C
	1 index cvx exec exch sub def
} def
/ifcase 
{ 	% syntax: pattern { {match1 {proc1}} {match2 {proc2}} ...} ifcase
	% if match is /default, it will be executed immediately
	% pattern is on the stack at the start of any proc.
	% proc should really remove it.
  	exch /pattern edef 
	{
		aload pop exch dup
		/default eq {pop pattern exch exec exit} if
		pattern eq {pattern exch exec exit} {pop} ifelse
	} forall 
} def
/ToString {3 string cvs} def
/ChooseFont
{	% selects font and sets fbox
	/fbox edef
	findfont fbox scalefont setfont
} def
%-------------------------------------------------------------------------------
%-------Sizes: internal unit is font size.
%------------- also here is code to use real page size.
%------------------------------------------------------------------------------- 
/ptof {fbox div exch fbox div exch} def
/ftop {fbox mul exch fbox mul exch} def
/moverel {ftop rmoveto} def
/linerel {ftop rlineto} def
/StringWidth {stringwidth pop fbox div} def
/GetPageMargins
{
	clippath pathbbox	%get page size
	/TopMargin edef
	/RightMargin edef	%put it where I can use it.
	/BottomMargin edef
	/LeftMargin edef
	newpath	%stops me strokeing the clipping path
} def
/PageWidth {RightMargin LeftMargin ptof sub} def
/smaller
{
	exch 
	{	{/LeftMargin {exch plus}}
		{/RightMargin {exch minus}}
		{/TopMargin {exch minus}}
		{/BottomMargin {exch plus}}
	} ifcase
} def 
%-------------------------------------------------------------------------------
%-------Line,Page breaking code.
%-------------------------------------------------------------------------------
/Atom
{
	GetAtom
	currentpoint pop
	hbox fbox mul add
	RightMargin gt
	{NewLine} if
	currentpoint
	vbox fbox mul sub
	BottomMargin lt
	{NewPage} if pop
} def
/NewDoc
{	% begin a document
	% assumes margins have been set
	LeftMargin TopMargin moveto
	Verbatim %default style
	/Home save def
	/StyleDict 128 dict def
	StyleDict begin
} def
/NewStyle
{	% clean up and start again
	Flush end
	currentpoint 
	Home restore
	/Home save def
	moveto
	/StyleDict 128 dict def
	StyleDict begin
} def
/EndDoc
{
	Flush end
	showpage	%show what's left.
	Home
	restore
} def
/PageBreak
{	% when the user wants to insert a page break.
	EndDoc NewDoc
} def
%-------------------------------------------------------------------------------
%-------Chord data: a table taken from ChordPro, and put in
%------------------ the simpler format used here. Some mistakes corrected.
%------------------ Chordpro is (c) Mario Dorion & Martin Leclerc
%-------------------------------------------------------------------------------
/Chordata	% this is spinal tap!
[ 	
	[(Ab)[ 4 6 6 5 4 4 ]]		[(Abm)[ 4 6 6 4 4 4 ]]
	[(Ab7)[ -1 -1 1 1 1 2 ]]	[(Abm7)[ -1 -1 4 4 4 4 ]]
	[(Absus)[ -1 -1 1 1 2 4 ]]	[(Ab+)[ -1 -1 2 1 1 0 ]]
	[(Abdim)[ -1 -1 0 1 0 1 ]]	[(Abmaj7)[ -1 -1 1 1 1 3 ]]
	[(A)[ -1 0 2 2 2 0 ]]		[(Am)[ -1 0 2 2 1 0 ]]
	[(A7)[ -1 0 2 0 2 0 ]]		[(Am7)[ -1 0 2 2 1 3 ]]
	[(Asus)[ -1 -1 2 2 3 0 ]]	[(A+)[ -1 0 3 2 2 1 ]]
	[(Adim)[ -1 -1 1 2 1 2 ]]	[(Amaj7)[ -1 0 2 1 2 0 ]]
	[(A#)[ -1 1 3 3 3 1 ]]		[(A#m)[ -1 1 3 3 2 1 ]]
	[(A#7)[ -1 -1 3 3 3 4 ]]	[(A#m7)[ -1 1 3 1 2 1 ]]
	[(A#sus)[ -1 -1 3 3 4 1 ]]	[(A#+)[ -1 -1 0 3 3 2 ]]
	[(A#dim)[ -1 -1 2 3 2 3 ]]	[(A#maj7)[ -1 1 3 2 3 -1 ]]
	[(Bb)[ -1 1 3 3 3 1 ]]		[(Bbm)[ -1 1 3 3 2 1 ]]
	[(Bb7)[ -1 -1 3 3 3 4 ]]	[(Bbm7)[ -1 1 3 1 2 1 ]]
	[(Bbsus)[ -1 -1 3 3 4 1 ]]	[(Bb+)[ -1 -1 0 3 3 2 ]]
	[(Bbdim)[ -1 -1 2 3 2 3 ]]	[(Bbmaj7)[ -1 1 3 2 3 -1 ]]
	[(B)[ -1 2 4 4 4 2 ]]		[(Bm)[ -1 2 4 4 3 2 ]]
	[(B7)[ 0 2 1 2 0 2 ]]		[(Bm7)[ -1 2 4 2 3 2 ]]
	[(Bsus)[ -1 -1 4 4 5 2 ]]	[(B+)[ -1 -1 1 0 0 4 ]]
	[(Bdim)[ -1 -1 0 1 0 1 ]]	[(Bmaj7)[ -1 2 4 3 4 -1 ]]
	[(C)[ 0 3 2 0 1 0 ]]		[(Cm)[ -1 1 5 5 4 3 ]]
	[(C7)[ 0 3 2 3 1 0 ]]		[(Cm7)[ -1 1 5 3 4 3 ]]
	[(Csus)[ -1 -1 3 0 1 3 ]]	[(C+)[ -1 -1 2 1 1 0 ]]
	[(Cdim)[ -1 -1 1 2 1 2 ]]	[(Cmaj7)[ -1 3 2 0 0 0 ]]
	[(C#)[ -1 -1 3 1 2 1 ]]		[(C#m)[ -1 -1 2 1 2 0 ]]
	[(C#7)[ -1 -1 3 4 2 4 ]]	[(C#m7)[ -1 -1 2 4 2 4 ]]
	[(C#sus)[ -1 -1 6 6 7 4 ]]	[(C#+)[ -1 -1 3 2 2 1 ]]
	[(C#dim)[ -1 -1 2 3 2 3 ]]	[(C#maj7)[ -1 4 3 1 1 1 ]]
	[(Db)[ -1 -1 3 1 2 1 ]]		[(Dbm)[ -1 -1 2 1 2 0 ]]
	[(Db7)[ -1 -1 3 4 2 4 ]]	[(Dbm7)[ -1 -1 2 4 2 4 ]]
	[(Dbsus)[ -1 -1 6 6 7 4 ]]	[(Db+)[ -1 -1 3 2 2 1 ]]
	[(Dbdim)[ -1 -1 2 3 2 3 ]]	[(Dbmaj7)[ -1 4 3 1 1 1 ]]
	[(D)[ -1 -1 0 2 3 2 ]]		[(Dm)[ -1 -1 0 2 3 1 ]]
	[(D7)[ -1 -1 0 2 1 2 ]]		[(Dm7)[ -1 -1 0 2 1 1 ]]
	[(Dsus)[ -1 -1 0 2 3 3 ]]	[(D+)[ -1 -1 0 3 3 2 ]]
	[(Ddim)[ -1 -1 0 1 0 1 ]]	[(Dmaj7)[ -1 -1 0 1 1 1 ]]
	[(D#)[ -1 -1 5 3 4 3 ]]		[(D#m)[ -1 -1 4 3 4 2 ]]
	[(D#7)[ -1 -1 1 3 2 3 ]]	[(D#m7)[ -1 -1 1 3 2 2 ]]
	[(D#sus)[ -1 -1 1 3 4 4 ]]	[(D#+)[ -1 -1 1 0 0 4 ]]
	[(D#dim)[ -1 -1 1 2 1 2 ]]	[(D#maj7)[ -1 -1 1 3 3 3 ]]
	[(Eb)[ -1 -1 6 4 5 4 ]]		[(Ebm)[ -1 -1 4 3 4 2 ]]
	[(Eb7)[ -1 -1 1 3 2 3 ]]	[(Ebm7)[ -1 -1 1 3 2 2 ]]
	[(Ebsus)[ -1 -1 1 3 4 4 ]]	[(Eb+)[ -1 -1 1 0 0 4 ]]
	[(Ebdim)[ -1 -1 1 2 1 2 ]]	[(Ebmaj7)[ -1 -1 1 3 3 3 ]]
	[(E)[ 0 2 2 1 0 0 ]]		[(Em)[ 0 2 2 0 0 0 ]]
	[(E7)[ 0 2 2 1 3 0 ]]		[(Em7)[ 0 2 2 0 3 0 ]]
	[(Esus)[ 0 2 2 2 0 0 ]]		[(E+)[ -1 -1 2 1 1 0 ]]
	[(Edim)[ -1 -1 2 3 2 3 ]]	[(Emaj7)[ 0 2 1 1 0 -1 ]]
	[(F)[ 1 3 3 2 1 1 ]]		[(Fm)[ 1 3 3 1 1 1 ]]
	[(F7)[ 1 3 1 2 1 1 ]]		[(Fm7)[ 1 3 1 1 1 1 ]]
	[(Fsus)[ -1 -1 3 3 1 1 ]]	[(F+)[ -1 -1 3 2 2 1 ]]
	[(Fdim)[ -1 -1 0 1 0 1 ]]	[(Fmaj7)[ -1 3 3 2 1 0 ]]
	[(F#)[ 2 4 4 3 2 2 ]]		[(F#m)[ 2 4 4 2 2 2 ]]
	[(F#7)[ -1 -1 4 3 2 0 ]]	[(F#m7)[ -1 -1 2 2 2 2 ]]
	[(F#sus)[ -1 -1 4 4 2 2 ]]	[(F#+)[ -1 -1 4 3 3 2 ]]
	[(F#dim)[ -1 -1 1 2 1 2 ]]	[(F#maj7)[ -1 -1 4 3 2 1 ]]
	[(Gb)[ 2 4 4 3 2 2 ]]		[(Gbm)[ 2 4 4 2 2 2 ]]
	[(Gb7)[ -1 -1 4 3 2 0 ]]	[(Gbm7)[ -1 -1 2 2 2 2 ]]
	[(Gbsus)[ -1 -1 4 4 2 2 ]]	[(Gb+)[ -1 -1 4 3 3 2 ]]
	[(Gbdim)[ -1 -1 1 2 1 2 ]]	[(Gbmaj7)[ -1 -1 4 3 2 1 ]]
	[(G)[ 3 2 0 0 0 3 ]]		[(Gm)[ 3 5 5 3 3 3]]
	[(G7)[ 3 2 0 0 0 1 ]]		[(Gm7)[ 3 5 3 3 3 3 ]]
	[(Gsus)[ -1 -1 0 0 1 3 ]]	[(G+)[ -1 -1 1 0 0 4 ]]
	[(Gdim)[ -1 -1 2 3 2 3 ]]	[(Gmaj7)[ -1 -1 5 4 3 2 ]]
	[(G#)[ 4 6 6 5 4 4 ]]		[(G#m)[ 4 6 6 4 4 4 ]]
	[(G#7)[ -1 -1 1 1 1 2 ]]	[(G#m7)[ -1 -1 4 4 4 4]]
	[(G#sus)[ -1 -1 1 1 2 4 ]]	[(G#+)[ -1 -1 2 1 1 0 ]]
	[(G#dim)[ -1 -1 0 1 0 1 ]]	[(G#maj7)[ -1 -1 1 1 1 3 ]]
] def 
%-------------------------------------------------------------------------------
%-PARSERS-----------------------------------------------------------------------
% This new section is to allow different methods of entry in different styles.
% There is a plan to allow the program to parse ASCII tab, and also for
% a possible interface with TabEdit, or other programs.
%-------------------------------------------------------------------------------
/StdParser
{ %the usual parser, for tablature.
	/Parse
	{ 
		/lastwasname false def
		/barcols 0 def
		{ % open ({) loop
			({) search exch
			{ % open (,) loop
				(,) search exch
				{ %loop again
					(\n) search exch
					{ %loop again
						( ) search exch
						dup length 0 ne
						{TabHandler}
						{pop} ifelse
						{pop}{exit} ifelse
					} loop	
 					{pop}{exit} ifelse
				} loop 
				{pop WriteColumn}{exit} ifelse	
			} loop 
			{pop}{exit} ifelse
			(}) search % assumed true
			pop exch pop
			(:) search
			{exch pop TextHandler}
			{MarkHandler} ifelse	
		} loop 
		WriteColumn
		0 1 barcols 1 sub
		{
			BarArray exch get
		} for % get everything back
		barcols array astore
		Atom % 	linebreaks do printing.
		/cols barcols plus %more columns...
		/bars 1 plus %and another bar.
	} def
	/WriteColumn
	{ %push column to stack; make a fresh column
		lastwasname
		{
			DefaultColumn DefaultString get
			dup length array copy
			CurrentColumn DefaultString
			3 -1 roll put
		} if
		/lastwasname false def
		BarArray barcols [0 CurrentColumn]  put
		/barcols barcols 1 add def
		/CurrentColumn BlankColumn rows array
		copy def %Do this every time.
	} def
	/IsTextRow
	{	% put text into column.
		CurrentColumn exch 3 -1 roll put
	} def
	/IsRow
	{ %if last was row too, fill it in.
		lastwasname
		{
			DefaultColumn DefaultString get
			dup length array copy
			CurrentColumn DefaultString
			3 -1 roll put
		} if
		/DefaultString edef
		/lastwasname true def
	} def
	/IsFret
	{	
		/lastwasname false def 
		1 array dup 0 3 index put
		CurrentColumn DefaultString
		2 index put
		DefaultColumn DefaultString
		2 index put
		pop pop
	} def
	/MarkHandler
	{% what to do with special marks.
		CurrentColumn DefaultString get
		0 get % for sensible use, we must set this
		dup length 0 eq % if it's not already set.
		{	pop DefaultColumn DefaultString get
			0 get /lastwasname false def} if
		exch
		{
			{ (tie) {pop 1 2} }	{ (up) 	{pop 2 2} }
			{ (down) {pop 3 2} }	{ (h) 	{pop 4 2} }
			{ (p) 	{pop 5 2} }	{ (harm){pop 6 2} }
			{ (vib) {pop 8 2} }	{ (0) 	{pop 7 (0) 3} }
			{ (1) 	{pop 7 (1) 3} }	{ (2) 	{pop 7 (2) 3} }
			{ (3) 	{pop 7 (3) 3} }	{ (4) 	{pop 7 (4) 3} }
		} ifcase
	 	array astore CurrentColumn DefaultString 3 -1 roll put
	} def
} def
%-------------------------------------------------------------------------------
%-------ASCIIparser: puts any marks that aren't - into the tab. ignores first
%------------------- and last thing to avoid spurious barlines.
%-------------------------------------------------------------------------------
/ASCIIparser
{
	/WholeBar rows array def
	/WholeLine rows array def
	BlankColumn WholeLine copy /WholeLine def
	BlankColumn WholeBar copy /WholeBar def
 	/Parse
	{ %parse ascii tab.
		0 1 rows 2 sub
		{
			exch
			(\n) search pop %must be true
			WholeLine exch 5 -1 roll exch put
			pop
		} for 
		%tab now split into rows. now generate columns.
		WholeLine rows 1 sub 3 -1 roll put
		{
			
			/barcols 0 def /alldone true def
			/row 0 def
			{
				WholeLine row get (|) search
				{	/alldone false def
					WholeBar row 3 -1 roll put
					pop WholeLine row 3 -1 roll put
				}
				{ WholeBar row 3 -1 roll put
					WholeLine row () put
				} ifelse
				/row 1 plus
				row rows eq {exit} if
			} loop
			WholeBar
			{
				(-) search
				{	3 1 roll pop pop
					dup length 1 sub 0 1 3 -1 roll
					{1 index exch (-) 0 get put} for pop
				}{pop} ifelse
			} forall
			{
				/finished true def
				/makecolumn false def
				/row 0 def
				WholeBar
				{
					(-) search
					{
						/finished false def
						pop 0 ( ) 0 get put
						(-) search dup 
						{4 1 roll exch pop exch pop}
						{exch} ifelse
						dup dup 4 1 roll length dup 0 ne
						{3 -1 roll makecolumn or /makecolumn edef}
						{3 -1 roll pop} ifelse
						% stick it in the column.
						string copy 1 array dup 0 4 -1
						roll put 
						CurrentColumn row 
						3 -1 roll put
						%left with a copy of the string
						%fill it with minus signs.
						dup length 1 sub 0 1 3 -1 roll
						{1 index exch (-) 0 get put} for pop
					}
					{	
						pop
					} ifelse
					/row 1 plus
				} forall
				makecolumn
				{ % write a column !
					/row 0 def
					%needs to blank out later columns.
					BarArray barcols [0 CurrentColumn]  put
					/barcols barcols 1 add def
					/CurrentColumn BlankColumn rows array
					copy def %Do this every time.
				} if	
				finished {exit} if
			} loop
			barcols 0 ne
			{
				0 1 barcols 1 sub
				{
					BarArray exch get
				} for % get everything back
				barcols array astore
				Atom % 	linebreaks do printing.
				/cols barcols plus %more columns...
				/bars 1 plus %and another bar.
			} if
			alldone {exit} if
		} loop
	} def
} def
%-------------------------------------------------------------------------------
%-STYLES------------------------------------------------------------------------
% In this section I define some styles in which
% the program will print. You can add more, but
% don't change these.
%-------------------------------------------------------------------------------
%-------Tablature: this is an engine for printing tablature
%----------------- in a very general way. It needs some externally
%----------------- supplied information to work.
%-------------------------------------------------------------------------------
/Tablature
{
	/BlankColumn edef
	/rows BlankColumn length def
	/DefaultColumn BlankColumn rows array copy def %One-shot initalise
	/DefaultString 1 def% first string.
	/CurrentColumn BlankColumn rows array copy def %Do this every time.
	/BarArray 128 array def %very generous too!
	% Initialise variables.
	/hbox 0 def /cols 0 def /bars 0 def
	BlankColumn 
	0 1 rows 1 sub
	{ 	dup 2 index exch get type cvlit
		/arraytype eq
		{neg 0.25 add /top edef exit}
		{pop} ifelse
	} for
	rows 1 sub -1 0
	{ 	dup 2 index exch get type cvlit
		/arraytype eq
		{neg 0.25 add /bottom edef exit}
		{pop} ifelse
	} for
	/bottom top minus
	pop
	/vbox {rows 1 add} def
	/, {Parse} def
	/NewPage {showpage LeftMargin TopMargin moveto} def	
	/NewLine
	{
		bars 0 eq
		{  	%very long bar. attempts to recover,
			%but an extra bar line gets drawn.
			/bars 1 def /cols barcols def
			/Justify PageWidth hbox sub cols div def
			Display
			/bars -1 def /cols barcols neg def /hbox 0 def 
		}
		{ %/Justify 0 def
			/hbox barbox minus
			/Justify PageWidth hbox sub cols div def
			bars 1 add 1 roll % stick this one on the bottom
			Display
			/bars 0 def /cols 0 def /hbox barbox def
		} ifelse
		LeftMargin currentpoint vbox fbox mul sub 
		exch pop moveto %usual newline
	} def
	/Flush
	{
		Parse
		/Justify 0 def 	% Don't justify
		Display %don't bother cleaning up-we're outta here
		LeftMargin currentpoint vbox fbox mul sub 
		exch pop moveto %usual newline
	}	def
	/Display
	{	%Draw bar line, tab all columns, draw bar line..
		gsave
		0 top moverel
		0 bottom linerel
		stroke	grestore
		bars 1 sub -1 0
		{	index % ...not reverse order	
			[2 BlankColumn] TabColumn
			{	%tab a single column.
				TabColumn
			} forall gsave
			0 top moverel
			0 bottom linerel
			stroke grestore
		} for
		bars {pop} repeat
	} def 
	/TabColumn
	{	/finger (x) def
		dup 0 get /cbox edef 1 get gsave
		{ %forall loop
			gsave dup type cvlit 
			/arraytype eq
			{ 
				/tie 0 def dup length
				{{1 	{pop}}
				 {2 	{pop dup 1 get /tie edef}}
				 {3 	{pop dup dup 1 get /tie
					 edef 2 get /finger edef}}
				} ifcase
				0 get dup StringWidth
				cbox exch sub Justify add /rbox edef
				show gsave 0 0.25 moverel
				rbox 0 linerel stroke grestore
				SpecialMarks
			}{show} ifelse
			grestore 0 -1 moverel
		} forall
		grestore cbox Justify add 0 moverel
	} def
	/GetAtom
	{	% needs to set: top,bottom,barcols,barbox,vbox
		dup %leave a copy on the stack.
		dup length 1 add /barcols edef
		/barbox 0 def %1 down!
		/previous [0] def
		/oldsbox 0 def /oldcbox 0 def
		{ %forall
			/cbox 0 def
			/sbox 0 def
			0 1 rows 1 sub
			{ % for loop...
				1 index 1 get% copy of array
				exch get % get this row
				dup type cvlit
				/arraytype eq
				{
					0 get %get the string
					StringWidth cbox max /cbox edef
				} 
				{
					StringWidth sbox max /sbox edef
				} ifelse
			} for
			sbox 0 gt 
			{%there is a string
				oldsbox oldcbox max 2 add
				dup barbox add /barbox edef
				previous 0 3 -1 roll put
				/oldsbox sbox def
				/oldcbox cbox def
			}
			{%there is no string!
				previous 0 oldcbox 2 add put
				oldcbox 2 add barbox add /barbox edef
				/oldsbox oldsbox oldcbox sub 2 sub def
				/oldcbox cbox def
			} ifelse
			/previous edef
		} forall
		previous 0 oldsbox oldcbox max 2 add put
		oldsbox oldcbox max 2 add barbox add /barbox edef
		/hbox barbox plus
	} def
	/SpecialMarks
	{	% produce all the extra bits of notation.
		gsave tie
		{	{1{pop	% code to do ties
				0.25 0 moverel
				rbox 0.5 sub 3 div -0.25  ftop
				rbox 0.5 sub 3 div 2 mul -0.25 ftop
				rbox 0.5 sub 0 ftop rcurveto stroke}} 
			{2{pop	% code to do slides up
				0.25 0 moverel
				rbox 0.5 sub 0.5 linerel stroke}} 
			{3{pop	% code to do slides down
				0.25 0.5 moverel
				rbox 0.5 sub -0.5 linerel stroke}}
			{4{pop	% code to do hammer on
				0.5 0.5 moverel 0.25 -0.5 linerel
				0.25 0.5 linerel stroke}}
			{5{pop	% code to do pull off
				0.5 0 moverel
				0.25 0.5 linerel
				0.25 -0.5 linerel stroke}}
			{6{pop	% code to do harmonic
				0.5 0.25 moverel 0.25 0.25 linerel
				0.25 -0.25 linerel -0.25 -0.25 linerel
				closepath stroke}}
			{7{pop	% code to do finger mark (specify fingering)
				gsave 1 0.25 moverel
				currentpoint newpath 
				fbox 2 div 0 360 arc
				gsave 1 setgray fill grestore 
				stroke grestore
				13 16 div  0 moverel
				finger ToString show}}				
			{8{pop	% code to do vibrato
				0.25 0.5 moverel
				3 {0.125 -0.125 linerel 0.125 0.125 linerel}
				repeat stroke}}
		} ifcase grestore
	} def
} def
%-------------------------------------------------------------------------------
%-------Verbatim: this is the default style. It's intended for reproducing
%---------------- blocks of text directly, such as an ASCII tab file.
%-------------------------------------------------------------------------------
/Verbatim
{
	/, {Parse} def 
	/vbox 1 def
	/Courier 8 ChooseFont
	/Parse
	{ % breaks into words.
		{	
			(\n) search exch
			{
				( ) search exch
				Atom Display
				{Atom Display}{exit} ifelse
			} loop
			{pop} {exit} ifelse
			NewLine
		} loop
		NewLine
	} def
	/GetAtom {dup StringWidth /hbox edef} def
	/Display {gsave 0 -1 moverel show grestore hbox 0 moverel} def
	/NewLine
	{	LeftMargin currentpoint vbox fbox mul sub
		exch pop moveto
	} def
	/NewPage {showpage LeftMargin TopMargin moveto} def	
	/Flush {Parse NewLine} def
} def
%-------------------------------------------------------------------------------
%-------Centred: This style produces centred text. It's intended for
%--------------- making titles.
%-------------------------------------------------------------------------------
/Centred
{
	/, {Parse} def 
	/vbox 1 def
	/Helvetica 12 ChooseFont
	/Parse
	{ % breaks into words.
		{
			(\n) search exch 
			{
				dup
				( ) search
				{
					3 1 roll
					0 (\267) putinterval
					pop 
					Atom pop dup
					(\267) search pop
					exch pop
					( ) search
					{
						pop pop pop
						exch pop	
					}
					{
					 	pop pop
					} ifelse
				}
				{
					pop Atom exit
				} ifelse
			} loop
			NewLine pop
			{pop} {exit} ifelse
		} loop
	} def
	/GetAtom {dup StringWidth /hbox edef} def
	/Display
	{
		dup dup
		{
			(\267) search
			{pop 0 ( ) putinterval}
			{pop exit} ifelse
		} loop
		gsave PageWidth hbox sub 2 div -1 moverel
		show grestore
	}def
	/NewLine
	{
		Display
		LeftMargin currentpoint vbox fbox mul sub
		exch pop moveto
	} def
	/NewPage {showpage LeftMargin TopMargin moveto} def	
	/Flush {Parse} def
} def
%-------------------------------------------------------------------------------
%-------Verses: Each block of text is assumed to be a verse, and this
%-------------- style tries to place as many verses horizontally as it can.
%-------------------------------------------------------------------------------
/Verses
{ 
	/rows 0 def
	/vbox 0 def
	/Times-Roman 8 ChooseFont
	/, {Parse} def
	/Parse
	{	/hbox 0 def
		{
			(\n) search exch Atom exch
			{exch pop exch} {exit} ifelse
		} loop
		Display
	} def
	/GetAtom
	{	dup StringWidth
		hbox max /hbox edef
		/rows 1 plus
		rows vbox max /vbox edef
	} def
	/NewLine
	{
		LeftMargin currentpoint vbox 1 add fbox mul sub
		exch pop moveto %usual def ...
		/vbox  rows def % and reset vbox
	} def
	/NewPage
	{
		showpage
		LeftMargin TopMargin moveto %usual def..
		/vbox rows def % and reset vbox
	} def
	/Display
	{ % show whole verse
		rows -1 1
		{
			gsave
			neg 0 exch moverel
			show grestore %start popping strings
		} for
		/rows 0 def % reset rows
		hbox 1 add 0  moverel
		/hbox 0 def % reset hbox too.
	} def
	/Flush {Parse NewLine} def
} def
%-------------------------------------------------------------------------------
%-------Chords: This style prints chord diagrams. It 'knows' over
%-------------- 130 chords, but you can use your own.
%-------------------------------------------------------------------------------
/Chords
{
	/, {Parse} def
	/vbox 9 def
	/Times-Roman 8 ChooseFont
	/Parse {Atom Display} def
	/Flush {Parse NewLine} def
	/CentreShow
	{	% centre a string horizontally and vertically
		gsave
		dup StringWidth
		2 div neg -0.3 moverel% horizontal
		show grestore	%back to centre
	} def
	/GetAtom
	{		% first pass, find range, also diagram width.
		dup type cvlit
		/stringtype eq
		{	%find it in Chordata
			Chordata
			{
				dup 0 get 2 index eq
				{	%found it
					1 get
					exit % stop search
				}
				{pop} ifelse
			} forall
			dup type cvlit /stringtype eq
			{ %there was no match
				[-1 -1 -1 -1 -1 -1] % rescue program
			} if
		} if % no action otherwise
		dup dup length /cols edef % width of diagram.
		/top -2 def
		/bottom 99 def
		{
			dup type cvlit
			/arraytype eq 
			{	0 get	} if
			%pop % don't want string this time round.
			dup
			top max /top edef %highest fret
			dup 
			0 gt	%ignore 0 fret, unplayed strings
			{	bottom min /bottom edef	}
			{	pop	}	ifelse
		} forall
		top 5 le
		{	/top 5 def	/bottom 0 def	}
		{	/top bottom 5 add def
			bottom 1 sub /bottom edef
		} ifelse
		/hbox cols 2 add def	
	} def
	/Display
	{ %style object.
		gsave
		0.5 -1 moverel
		gsave
		-1 -1 -6 
		{
			1 exch moverel
			cols 1 sub 0 linerel stroke
			grestore gsave
		} for
		bottom 0 eq
		{	% gotta draw extra line.
			1 -0.875 moverel cols 1 sub 0 linerel stroke	% ok that's it.
		} if %label first fret elsewhere...
		grestore gsave 1 -0.5 moverel
		{	
			dup type cvlit
			/arraytype eq
			{	aload pop ToString }
			{	()	} ifelse
			exch dup gsave % draw string
			0 -0.5 moverel 0 -5 linerel stroke
			grestore gsave 0 le
			{ % something is printed here
				-1 eq
				{	(x) CentreShow	}
				{ 	(o) CentreShow	}
				ifelse pop	% if we did that,that's this string done.
			} 	
			{ % figure out where to put this string
				bottom sub neg 0 exch moverel
				gsave currentpoint newpath
				0.5 fbox mul 0 360 arc
				gsave 1 setgray fill grestore
				stroke grestore CentreShow 
			} ifelse
			grestore
			1 0 moverel
		} forall
		bottom 0 ne
		{ %   label first fret.
			0 -0.5 moverel
			bottom ToString CentreShow
		} if
		grestore
		cols 1 add 2 div -7 moverel
		CentreShow	%write name centred.
		grestore
		cols 2 add 0 moverel
	} def
	/NewLine
	{	LeftMargin currentpoint vbox fbox mul sub
		exch pop moveto
	} def
	/NewPage {showpage LeftMargin TopMargin moveto} def	
} def
%-------------------------------------------------------------------------------
%-------ChordPro: This style prints chords above lyrics, a la ChordPro
%-------------------------------------------------------------------------------
/ChordPro
{
	/vbox 3 def
	/Times-Roman 8 ChooseFont
	/, {Parse} def
	/Flush {Parse NewLine} def
	/Parse
	{	%split into atoms
		{
			(\n) search exch
			{
				([) search
				{
					dup length 0 ne
					{ Atom Display }
					{ pop } ifelse
					pop
				}
				{ Atom Display exit } ifelse
			} loop
			{pop NewLine} {exit} ifelse
		} loop
	} def
	/GetAtom
	{ 	% get width attributes of atom
		/hbox 0 def
		dup
		(]) search % contains a chord ?
		{	StringWidth 1 add /hbox edef pop
			StringWidth hbox max /hbox edef	}
		{	StringWidth /hbox edef		} ifelse
	}def
	/Display
	{
		(]) search % contains a chord ?
		{	gsave 0 -1 moverel
			show grestore pop } if
		gsave 0 -2 moverel
		show grestore hbox 0 moverel
	} def
	/NewLine
	{
		LeftMargin currentpoint vbox fbox mul sub
		exch pop moveto
	} def
	/NewPage {showpage LeftMargin TopMargin moveto} def	
} def
%-------------------------------------------------------------------------------
%-------Guitar: an example of a style that uses Tablature. It defines the
%-------------- things that Tablature needs to know, for printing guitar
%-------------- tab with a row of text above & below.
%-------------------------------------------------------------------------------
/Guitar
{	% a tab style. this must come BEFORE 'Tablature'

	/Times-Roman 8 ChooseFont
	StdParser % usual method of entry.
	/TextHandler
	{% what to do with text.depends how many text objects you have.
		{
			{ (chord) {pop 0 IsTextRow} }
			{ (lyric) {pop 7 IsTextRow} }
		} ifcase
	} def
	
	/TabHandler
	{% what you call the rows that contain strings.
		{
			{ (e) {pop 1 IsRow} }
			{ (B) {pop 2 IsRow} }
			{ (G) {pop 3 IsRow} }
			{ (D) {pop 4 IsRow} }
			{ (A) {pop 5 IsRow} }
			{ (E) {pop 6 IsRow} }
			{ /default {IsFret}}
		} ifcase
	} def
	%template

	[() [()][()][()][()][()][()] ()]
} def
/ASCIItab
{	% a tab style. this must come BEFORE 'Tablature'

	/Times-Roman 8 ChooseFont
	[[()][()][()][()][()][()]]
	Tablature
	ASCIIparser
} def
%-------------------------------------------------------------------------------
%-DOCUMENT SETUP----------------------------------------------------------------
%This section defines the margins of the page, and
%the line thickness used in the program. you may want
%to change some of this.
%-------------------------------------------------------------------------------
GetPageMargins
/LeftMargin 1 inch smaller
/RightMargin 1 inch smaller
/TopMargin 1 inch smaller
/BottomMargin 1 inch smaller
0.1 setlinewidth
/Text
{
	/Times-Roman 8 ChooseFont
} def
%-------------------------------------------------------------------------------
%-DOCUMENT----------------------------------------------------------------------
% Your PStab files are added beyond this point.
%-------------------------------------------------------------------------------