Skip to content

Commit 9bbd2c6

Browse files
authored
Merge pull request #30 from demaere-oiie/bytebeat
Bytebeat
2 parents c63118a + b5fa71a commit 9bbd2c6

File tree

3 files changed

+211
-3
lines changed

3 files changed

+211
-3
lines changed

examples/bytebeat.psh

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// Partial ByteBeat imp: http://viznut.fi/texts-en/bytebeat_deep_analysis.html
2+
//
3+
// at the moment, literals must be decimal
4+
//
5+
// thus far, only the following operators are supported; precedences taken
6+
// from https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Expression_evaluation_order
7+
8+
let ops = ["*","&","|",">>","<<", "^", "-", "+", "/", "%"];
9+
let prc = [5, 11, 13, 7, 7, 12, 6, 6, 5, 5];
10+
11+
// cargo run examples/bytebeat.psh ["bytebeat expr"] [seconds]
12+
13+
//------------------------------------------------------------------------------
14+
// AST
15+
16+
class Xpr {
17+
init(self, op, l, r) {
18+
self.op = op;
19+
self.l = l;
20+
self.r = r;
21+
}
22+
eval(self, t) {
23+
if (self.op == "*") {
24+
return self.l.eval(t) * self.r.eval(t);
25+
} else if (self.op == "&") {
26+
return self.l.eval(t) & self.r.eval(t);
27+
} else if (self.op == "|") {
28+
return self.l.eval(t) | self.r.eval(t);
29+
} else if (self.op == ">>") {
30+
return self.l.eval(t) >> self.r.eval(t);
31+
} else if (self.op == "<<") {
32+
return self.l.eval(t) << self.r.eval(t);
33+
} else if (self.op == "^") {
34+
return self.l.eval(t) ^ self.r.eval(t);
35+
} else if (self.op == "+") {
36+
return self.l.eval(t) + self.r.eval(t);
37+
} else if (self.op == "-") {
38+
return self.l.eval(t) - self.r.eval(t);
39+
} else if (self.op == "/") {
40+
return self.l.eval(t) _/ self.r.eval(t);
41+
} else if (self.op == "%") {
42+
return self.l.eval(t) % self.r.eval(t);
43+
}
44+
return 0;
45+
}
46+
to_s(self) {
47+
return "(" + self.l.to_s() + self.op + self.r.to_s() + ")";
48+
}
49+
}
50+
51+
class Var {
52+
init(self) {
53+
}
54+
eval(self, t) {
55+
return t;
56+
}
57+
to_s(self) {
58+
return "t";
59+
}
60+
}
61+
62+
class Lit {
63+
init(self, v) {
64+
self.v = v;
65+
}
66+
eval(self, t) {
67+
return self.v;
68+
}
69+
to_s(self) {
70+
return self.v.to_s();
71+
}
72+
}
73+
74+
//------------------------------------------------------------------------------
75+
// Parsing (quick and dirty)
76+
77+
fun toktype(c) {
78+
if (48 <= c && c <= 57) { return 0; }
79+
else if (97 <= c && c <= 122) { return 1; }
80+
else if (65 <= c && c <= 90) { return 1; }
81+
else if (40 <= c && c <= 41) { return 2; }
82+
else { return 3; }
83+
}
84+
85+
class ParseCtx {
86+
init(self, s) {
87+
self.s = s;
88+
self.i = 0;
89+
self.tok = "";
90+
}
91+
token(self) {
92+
return self.tok;
93+
}
94+
lex(self) {
95+
if (self.i == self.s.len) {
96+
self.tok = "$";
97+
return self;
98+
}
99+
self.tok = "";
100+
let t = toktype(self.s.byte_at(self.i));
101+
loop {
102+
if (self.i == self.s.len ||
103+
self.s.byte_at(self.i) == 32) {
104+
loop {
105+
if(self.i == self.s.len ||
106+
self.s.byte_at(self.i) != 32) {
107+
break;
108+
}
109+
self.i = self.i + 1;
110+
}
111+
return self;
112+
}
113+
let b = self.s.byte_at(self.i);
114+
if (t == toktype(b)) {
115+
self.tok = self.tok + String.from_codepoint(b);
116+
self.i = self.i + 1;
117+
} else {
118+
return self;
119+
}
120+
if (t == 2) { return self; } // parens are always single
121+
}
122+
}
123+
}
124+
125+
fun getprc(o) {
126+
for(let var i = 0; i < ops.len; ++i) {
127+
if(ops[i] == o) {
128+
return prc[i];
129+
}
130+
}
131+
return 100;
132+
}
133+
134+
fun prim(pc) {
135+
let tok = pc.token();
136+
if (tok == "t") {
137+
return Var();
138+
} else if (tok == "(") {
139+
let v = texpr(pc);
140+
pc.token() == ")"; // TODO: verify!
141+
return v;
142+
} else {
143+
return Lit(tok.parse_int(10));
144+
}
145+
}
146+
147+
fun expr(pc, n) {
148+
let var a = prim(pc);
149+
pc.lex();
150+
loop {
151+
let tok = pc.token();
152+
let p = getprc(tok);
153+
if (p < n) {
154+
a = Xpr(tok, a, expr(pc.lex(), p));
155+
} else {
156+
return a;
157+
}
158+
}
159+
}
160+
161+
fun texpr(pc) {
162+
return expr(pc.lex(), 100);
163+
}
164+
165+
// let bb2 = texpr(ParseCtx("(t*5&t>>7)|(t*3&t>>10)"));
166+
// let sample_val = ((t<<1)^((t<<1)+(t>>7)&t>>12))|t>>(4-(1^7&(t>>19)))|t>>7;
167+
168+
//------------------------------------------------------------------------------
169+
// Playback
170+
171+
fun main() {
172+
let SAMPLE_RATE = 8000;
173+
let dev = $audio_open_output(SAMPLE_RATE, 1);
174+
175+
let s = ($cmd_num_args() > 1 ? $cmd_get_arg(1) : "t*(t>>9|t>>13)&16");
176+
let d = ($cmd_num_args() > 2 ? $cmd_get_arg(2) : "x").parse_int(10);
177+
178+
let bb = texpr(ParseCtx(s));
179+
let end_time = $time_current_ms() + (d==nil ? 5 : d)*1000;
180+
181+
let var t = 0;
182+
183+
fun gen_samples(bb, num_samples) {
184+
let samples = ByteArray.with_size(num_samples * 4);
185+
186+
for (let var i = 0; i < num_samples; ++i) {
187+
samples.store_f32(i, (bb.eval(t)%256)/127 - 1.0);
188+
t = (t+1) % 8000;
189+
}
190+
191+
return samples;
192+
}
193+
194+
$println(bb.to_s());
195+
196+
loop {
197+
let msg = $actor_recv();
198+
199+
if (msg instanceof AudioNeeded) {
200+
$audio_write_samples(dev, gen_samples(bb, msg.num_samples));
201+
}
202+
if ($time_current_ms() > end_time) {
203+
break;
204+
}
205+
}
206+
}
207+
208+
main();

plush.tmbundle/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "plush",
33
"displayName": "Plush",
44
"description": "Syntax highlighting for Plush using TextMate grammar",
5-
"version": "1.0.4",
5+
"version": "1.0.5",
66
"repository": {
77
"type": "git",
88
"url": "git+https://github.com/maximecb/plush.git",

src/audio.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ pub fn audio_open_output(actor: &mut Actor, sample_rate: Value, num_channels: Va
116116
let sample_rate = sample_rate.unwrap_u32();
117117
let num_channels = num_channels.unwrap_u32();
118118

119-
if sample_rate != 44100 {
120-
return Err("for now, only 44100Hz sample rate supported".into());
119+
if sample_rate != 44100 && sample_rate != 8000 {
120+
return Err("for now, only 44100Hz or 8000Hz sample rates supported".into());
121121
}
122122

123123
if num_channels > 1 {

0 commit comments

Comments
 (0)