-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.rkt
115 lines (100 loc) · 2.91 KB
/
main.rkt
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
#lang racket
;; Program = (tempo N) top-expr ...
;;
;; top-expr = (play expr)
;; | (define id expr)
;;
;; expr = N
;; | (list N ...)
;; | player-expr
;; | id
;;
;; player-expr = (player N sound-expr ...)
;;
;; sound-expr = [sound (list N ...)]
;;
;; sound = hihat
;; | kick
;; | snare
;; | bassdrum
;; | crash
(require (for-syntax syntax/parse)
"lib/mel-live-lib.rkt")
(provide
; Override module begin
(rename-out [mel-module-begin #%module-begin]
[mel-datum #%datum]
[mel-quote quote]
[player-from-instrument player]
[set-loop loop]
[set-pitches pitch]
[set-reverb reverb])
; Racket basics
define require #%app lambda
; Library things
bassdrum hihat kick snare crash synth synth2
; Keys
Cmaj C#maj Dmaj D#maj Emaj Fmaj F#maj Gmaj G#maj Amaj A#maj Bmaj
Cmin C#min Dmin D#min Emin Fmin F#min Gmin G#min Amin A#min Bmin
midi)
;; The song
(define cursong '())
;; syntax class for player-expressions
(begin-for-syntax
(define-syntax-class player-expr
#:datum-literals (player loop pitch reverb)
(pattern (player arg ...))
(pattern (loop arg ...))
(pattern (pitch arg ...))
(pattern (reverb arg ...))
(pattern x:id
#:fail-unless #'(~player-expr x) "Incorrect type: expected player-expression")))
;; module-begin
(define-syntax mel-module-begin
(syntax-parser
[(_ ((~datum tempo) t)
(~seq (~or ((~datum define) id expr)
pexpr:player-expr) ...))
#:with defines #'(begin (define id expr) ...)
#:with plays #'(begin (play pexpr) ...)
#'(#%module-begin
(update-tempo t)
defines
plays
(play-song cursong))]))
;; Syntax -> Void
;; EFFECT plays this sound at a given time
(define-syntax (play stx)
(if (equal? (syntax-local-context) 'module)
(syntax-parse stx
[(_ n:nat)
(error "invalid syntax - play must take a player-expression")]
[(_ (list l:nat ...))
(error "invalid syntax - play must take a player-expression")]
[(_ player-expr)
#:with fin-player #'player-expr
#'(update-song fin-player)])
#'(error "Play is a top level form!")))
;; Restrict available datatypes to numbers, lists of numbers, and identifiers
(define-syntax mel-datum
(syntax-parser
[(_ . x:nat)
#'(#%datum . x)]
[(_ x:id)
#'(#%datum x)]
[(_ #`(list #,x:nat ...))
#'(#%datum (list x ...))]))
;; Mel's quote can only make lists of numbers
(define-syntax mel-quote
(syntax-parser
[(_ (n:number ...))
#'(quote (n ...))]))
;; Runtime helper to create the song
(define (update-song player)
(set! cursong (cons player cursong)))
(module reader syntax/module-reader
mel
#:read
read
#:read-syntax
read-syntax)