-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME.txt
191 lines (156 loc) · 7.74 KB
/
README.txt
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
SchArpeggio - A Scheme Music Arpeggiator
Jeremy Poulin and Mike Stowell
______________________________________________________________________________
Code:
- driver.rkt
- arpeggiator.rkt
- drawing.rkt
- objects.rkt
______________________________________________________________________________
Overall structure:
The user interacts with driver.rkt providing input for both a path to
save the dynamic sheet and the chord configurations to arpeggiate over.
The chord configurations, defined in objects.rkt along with many additional
objects and hash references, are then sent to drawing.rkt and
arpeggiator.rkt. Drawing.rkt draws out the chord configuration and saves
the file path defined by the user in the driver. Arpeggiator.rkt performs
music synthesis and plays out the sound, constantly sending drawing.rkt
single notes to draw as the music is playing.
______________________________________________________________________________
Who worked on what:
Mike was responsible for the majority of the driver code, some of the objects,
and the entirety of the drawing file. Jeremy was responsible for extending the
driver, many additional objects, and the entirety of the arpeggiator.
Code comments are left in the objects file to point out who worked on what.
______________________________________________________________________________
How the code exhibits key ideas of the course:
>> Mike <<
- Data abstraction and message passing are used in many objects like the
chord-configuration.
- String and symbolic manipulation is used to transform user input into
something our program can understand.
- Notes are drawn using a recursive function.
- Heavy use of let statements prevent tedious code repetitions in the
drawing program.
- Hash tables are kept to perform lookups on notes and their properties.
- Lists are utilized to allow easy passing of multiple chord configurations.
- Optional arguments allow procedures like that which draws a musical staff
behave differently on different input.
- Begin is used heavily in the draw-note procedure to allow multiple
s-expressions to be evaluated in one if-block.
>> Jeremy <<
- Data abstraction and message passing are used to interface with notes objects.
- Strings and symbolic manipulation are used to transform user input into
options/commands the arpeggiator understands.
- Progressions are played in a recursive fashion.
- A let statement provides internal variables for the play-chord function.
- Hash tables are used to organize both notes and their relative positions.
- Lists are manipulated to allow the user to play notes in different orders.
- If and cond statements allow configuration for different sounds.
- Begin is the foundation of the core functionality for playing multiple notes
in the same chord.
- A lambda function provides a handle for multi-threading.
______________________________________________________________________________
How to run the code:
- install qjackctl, jack, and supercollider
- reroute pulseaudio to dump its output to jack
- run a startup script to make jack your default sound provider
- download the source for rsc3
- install the source for rsc3 into drracket using raco
- start qjackctl
- start the supercollider server
- reconnect the sound ports so that the supercollider gives its outpt
to jack and jack gives its input to supercollider
- run our code
- and finally, reinstall linux at your convenience to undo the horrible things
you just did to your sound set-up
In other words, it is inadvisable to run our code. I've tried to make a youtube
video demo of our project, but I can't because Ubuntu's desktop recording applications
are as broken as the rest of the operating system. Cheers!
______________________________________________________________________________
Code blocks we are happy with:
>> Mike <<
I am quite content with this block of code in drawing.rkt:
; fill in the note if needed
(define (draw-fill-in speed)
(if (or (equal? speed quarter)
(equal? speed eighth)
(equal? speed sixteenth))
(begin
(move-offset 0 -1)
(fill-in-helper 5)
(move-offset 0 1)
)
(nothing)
)
)
(define (fill-in-helper level)
(if (= level 0)
(nothing)
(begin
(draw-offset level (- 0 level))
(draw-offset (- 0 level) (- 0 level))
(draw-offset (- 0 level) level)
(draw-offset level level)
(fill-in-helper (- level 1))
)
)
)
Programming in Scheme has made me think recursively a lot more often than
I would have. Had this have been any other language, I likely would have a
for or while loop. What draw-fill-in does is it fills in a note circle if
it is required (i.e. if it is a quarter, eighth, or sixteenth note).
The fill-in-helper was my clever way to recursively color in a note using
straight line. The draw-offset call draw a straight line up-right, up-left,
down-left, and finally down-right for "level" amount of pixels. This fills
in the note with a square rotated 45 degrees. The recursive call then
decrements the level and continues to draw concentric squares to fill in the
note.
I was also quite happy with how our giant hash table in objects.rkt came out.
This shared hash table is essentially the backbone to our entire application.
>> Jeremy <<
;; play note from a chord
(define (play-note-in-chord chord note-ref)
(draw-note (list-ref (chord 'notes) note-ref) (chord 'speed))
(define sound-func
(cond ((eq? (chord 'sound-font) triangle-wave) lf-tri)
((eq? (chord 'sound-font) saw-wave) lf-saw)
(else sin-osc)))
(even-out
(hash-ref note-length (chord 'speed))
((list-ref (chord 'notes) note-ref) 'name)
(sound-func
ar
((hash-ref note-with-name ((list-ref (chord 'notes) note-ref) 'name)) 'freq) 0)))
This block of code is the core of the arpeggiator - it not only allows configurable
sound wave selection, but also hands off the note information to Mike's drawing library.
Even-out is an function I made to make sure the sound output would go to both speakers -
otherwise it would just go the the left. Note-ref tells you which note in the chord to play,
and the hash tables provide the actual frequency and note information.
My second favorite code block is as follows:
; loops through chords objects and plays them sucessfully
(define (play-chord-progression prog)
(play-chord (car prog))
(play-chord-progression (append (cdr prog) (list (car prog)))))
This is my clever infinite loop control block that keeps the chords playing.
Essentially, I play the first chord, and then call the function recursively with the
car of the list appended to the cdr of the list. This ends up being an infite cycle,
which is wonderfully recursive. While it is possible to write functions like this
in other languages, I feel like this function truly exemplifies how racket changed
the way I code.
______________________________________________________________________________
Annoyances:
>> Mike <<
Drawing when you only have 3 basic functions - move, draw, and turn - is
quite difficult when you want circular objects. When browsing through the
drawing code, it may become obvious why some of the numbers were also
particularly annoying to deal with. Just 1 pixel off and everything gets
messed up.
>> Jeremy <<
Rsc3 is the worst sound library in the history of mankind. It is missing a key
feature of actual SuperCollider, namely patterns. Patterns would have increased
the sound quality of my arpeggiator, and most importantly allowed me to play notes
seperately instead of having a thread sleep and resetting the server to create
seperate notes from sound waves. I'm also note particularly fond of my play-chord
function. I could have made it recursive but chose not to because I was in a rush.
______________________________________________________________________________