«The Muse» by mkb

on 05 Sep'12 19:56 in reverse engineeringsequencerthe muse

emulator of Triadex's The Muse. Comments welcome; I've never used one of these things directly.

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
(
b = Bus.audio(s, 1);

SynthDef(\muse, {|freq, dur, vol|
	var env = EnvGen.kr(Env.linen(sustainTime: dur*0.925, attackTime: 0.075*dur, releaseTime: 0.01*dur), doneAction: 2);
	Out.ar(b, LPF.ar(Pulse.ar(freq, width: 0.5, mul: vol*env), 11000));
}).send(s);

SynthDef(\muse, {|freq, dur, vol|
	var env = EnvGen.kr(Env.linen(sustainTime: dur*0.98, attackTime: 0.01*dur, releaseTime: 0.01*dur), doneAction: 2);
	Out.ar(0, LPF.ar(Pulse.ar(freq, width: MouseX.kr(0.01, 0.99), mul: vol*env*MouseY.kr, add: Resonz.ar(Saw.ar(freq, mul: vol*env*MouseY.kr(1,0)), freq*1.2, 12)), 11000));
}).send(s);

SynthDef(\museverb, {
	Out.ar(0, Pan2.ar(FreeVerb.ar(In.ar(b), 0.45, 0.5)));
}).send(s);

)

(
	var counter0=0, counter1=0, shiftreg=rrand(0, pow(2,30).asInteger), handler, interval, theme, makeanote, tempo=320, basefreq=220, finefreq=0, rest=false, vol, slider, major, mminor, hminor, acc, lastmnote, mminorlook;
	var lookup;
	var mv = Synth(\museverb, [], s);
	var note = nil;
	interval = Array.with(2,8,10,20);
	theme = Array.with(5,7,25,20);
	slider = {
		|sliderval, i|
		var choice = 0;
		(sliderval == 0).if { choice = 0 }; // off
		(sliderval == 1).if { choice = 1 }; // on
		(sliderval == 2).if { choice = counter0 & 1 }; // c1/2
		(sliderval == 3).if { choice = counter0 & 2 >> 1 }; // c1
		(sliderval == 4).if { choice = counter0 & 4 >> 2 }; // c2
		(sliderval == 5).if { choice = counter0 & 8 >> 3 }; // c4
		(sliderval == 6).if { choice = counter0 & 16 >> 4 }; // c8
		(sliderval == 7).if { choice = (counter1 / 3).asInteger % 2 }; // c3
		(sliderval == 8).if { choice = (counter1 >= 6).asInteger }; // c6
		(sliderval >= 9 && (sliderval <= 39)).if { choice = (shiftreg >> (sliderval.asInteger - 9)) & 1 };
		choice;
	};		
		
	makeanote = { |freq|
		var dur;
		"makenote".postln;
		if (t == nil, { dur = 1 }, { dur = 2/t.tempo });
		
		if ((counter0 & 1) == 1 && (note != nil), 
			{note.set(\freq, freq, \vol, vol);},
			{note = Synth(\muse, [\freq, freq, \dur, dur, \vol, vol], mv, \addBefore);}
		);
	};
	
	handler = { 
		var notes, freq, parity, mnote;
		parity = theme.sum(slider).asInteger & 1;
		("shiftreg" + (shiftreg&0x7fffffff).asHexString).postln;
		notes = interval.collect(slider);
		mnote = notes[0] + (2 * notes[1]) + (4 * notes[2]);
		freq = (basefreq.cpsmidi + lookup[mnote]);
		("A"+freq).postln;
		if ((mminorlook == 1) &&
			((mnote == 5) || (mnote == 6)) &&
			(lastmnote != nil)
		, {
			if (lastmnote > mnote, {
				freq = freq - 1;
				freq.postln;
			});
		});
		lastmnote = mnote;
		freq = freq.midicps * (1 + notes[3]);
		("B"+freq).postln;
		("R"+rest).postln;
		("N"+notes.sum).postln;
		if (rest == false || (notes.sum != 0)) {
			makeanote.value(freq * finefreq);
		};
		("counter0" + counter0).postln;
		("counter1" + counter1).postln;
		if (counter0&1 == 1, {
			counter1 = (counter1+1) % 12;
			shiftreg = shiftreg << 1 | parity;
		});
		counter0 = (counter0+1) % 32;
	};
	
	Window.allWindows.do { |w| if (w.name == "The Muse") { w.close } };
	w = Window.new("The Muse", Rect(200,200,800,710));
	c = ControlSpec.new(0, 39, step: 1);
	t = TempoClock.new;
	
	EZSlider.new(w, Rect(0,0,800,75), "Interval A", c, { |ez| interval[0] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,75,800,75), "Interval B", c, { |ez| interval[1] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,150,800,75), "Interval C", c, { |ez| interval[2] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,225,800,75), "Interval D", c, { |ez| interval[3] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,300,800,75), "Theme W", c, { |ez| theme[0] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,375,800,75), "Theme X", c, { |ez| theme[1] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,450,800,75), "Theme Y", c, { |ez| theme[2] = ez.value}, initAction:true);
	EZSlider.new(w, Rect(0,525,800,75), "Theme Z", c, { |ez| theme[3] = ez.value}, initAction:true);
	
	EZSlider.new(w, Rect(0,600,400,40), "Volume", action: {|ez| vol = ez.value;}, initVal: 0.75, initAction:true);
	EZSlider.new(w, Rect(400,600,400,40), "Pitch", ControlSpec(0,127, step:1),action: {|ez| basefreq = ez.value.midicps;}, initVal: 32, initAction:true);
	EZSlider.new(w, Rect(0,640,400,40), "Fine Pitch", ControlSpec(1/1.0595465, 1.0595465), action: {|ez| finefreq = ez.value}, initVal: 1, initAction: true);
	~tempobutton = EZSlider.new(w, Rect(400,640,400,40), "Tempo", ControlSpec(12, 600), action: {|ez| if (t != nil) {t.tempo = ez.value / 60}}, initVal: 160, initAction: true);
	Button.new(w,Rect(0,680,80,30)).states_([["Start"],["Stop"]]).action_({
		|button|
		if ((button.value == 0), {
			"hold".postln;
			t.stop;
			t = nil;
		}, {
			"foof".postln;
			t = TempoClock.new(~tempobutton.value/60);
			mv.free;
			mv = Synth(\museverb, [], s);
			t.sched(0, { handler.value(lookup, basefreq); 1})
		});
	});
	Button.new(w,Rect(80,680,80,30)).states_([["Step"]]).action_({|button| handler.value(lookup, basefreq);});
	Button.new(w,Rect(160,680,80,30)).states_([["Reset"]]).action_({counter0 = counter1 = shiftreg = 0;});
	CheckBox.new(w, Rect(240,680,80,30), "Rest").action = { |state| rest = state.value };
	major = CheckBox.new(w, Rect(320,680,80,30), "Major").action = {
		"majorclick".postln;
		major.value.postln;
		if (major.value, {
			"majoron".postln;
			hminor.value = 0;
			mminor.value = 0;
			lookup = [0,2,4,5,7,9,11,12];
		});
		mminorlook = false;
	};
	
	hminor = CheckBox.new(w, Rect(400,680,80,30), "Harmonic").action = {
		"hmonirclick".postln;
		if (hminor.value, {
			"hmoniron".postln;
			major.value = 0;
			mminor.value = 0;
			lookup = [0,2,3,5,7,8,11,12]
		});
		mminorlook = false;
	};
	
	mminor = CheckBox.new(w, Rect(480,680,80,30), "Melodic").action = {
		"mmonirclick".postln;
		if (mminor.value, {
			"mminor".postln;
			hminor.value = 0;
			major.value = 0;
			lookup = [0,2,3,5,7,9,11,12]
		});
		mminorlook = true;
	};
	
	major.valueAction = true;
	~display = StaticText(w,Rect(0,800,40,710)).font_("Monaco").stringColor_(Color.gray(0,1));
	w.onClose = { t.stop };
	w.front;
)
raw 6190 chars (focus & ctrl+a+c to copy)
reception
comments