You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
12 KiB
Plaintext

(
var clockStringFunc, metronomeStringFunc, metronomeColorFunc, updateTransport, updateSubsection,
buildGenerator, buildMetronome, updateSection, buildTransport, buildTempoControl, buildMasterFader, buildTrackFader,
masterView, faderView, helpView, currentSection = 1, currentSubsection = 1;
// these funcs update the elements of the transport panel
clockStringFunc = {
arg measure, beat;
var measureString, beatString, leadSpace;
measureString = measure.asInteger.asString;
beatString = beat.asInteger.asString;
leadSpace = (3 - measureString.size).collect({" "}).join;
leadSpace ++ measureString ++ "." ++ beatString
};
// [-30, -105, -104] and [-30, -105, -113] are unicode inverse bullet and normal bullet, respectively
metronomeStringFunc = { arg beat; if(beat == 1,
{[-30, -105, -104].collect({arg int; int.asAscii}).as(String)},
{[-30, -105, -113].collect({arg int; int.asAscii}).as(String)})};
metronomeColorFunc = { arg beat; if(beat == 1, {Color.red},{Color.black})};
updateTransport = {arg clock, metronome, sectionDisplay, measure, beat, section, subsection;
sectionDisplay.string = "section: " ++ section.asInteger ++ "." ++ subsection.asInteger;
clock.string = clockStringFunc.value(measure, beat);
metronome.stringColor = metronomeColorFunc.value(beat);
metronome.string = metronomeStringFunc.value(beat);
{0.75.wait; {metronome.string = ""}.defer}.fork(~tempoClock, quant: 0);
}.inEnvir;
updateSubsection = {arg mod, clock, metronome, sectionDisplay, refresh = true;
if(~sectionNavDict[[currentSection, currentSubsection + mod]] != nil, {
currentSubsection = currentSubsection + mod;
if(refresh, {
updateTransport.value(clock, metronome, sectionDisplay,
~sectionNavDict[[currentSection, currentSubsection]][0], 1,
currentSection, currentSubsection
);
});
}, {
updateSection.value(mod, clock, metronome, sectionDisplay, refresh, true)
})
};
buildGenerator = {arg view;
var ranSeed;
HLayout(
ranSeed = TextField(view).string_("19800725"),
Button(view).states_([["reset seed"]]).action_({ ranSeed.string = "19800725"}.inEnvir),
Button(view).states_([["random seed"]]).action_({ ranSeed.string = 50000000.rand.asString}.inEnvir),
Button(view).states_([["generate"]]).action_({
{~genAll.value(ranSeed.string.asInteger); ~appStatus.string = "status: ready"}.fork(AppClock);
~appStatus.string = "status: generating"}.inEnvir),
[~appStatus = StaticText(view).string_("status: ready"), stretch: 1],
Button(view).states_([["transcribe"]]).action_({
{~transcribe.value(~scoreData, ~sectionData, ranSeed.value); ~appStatus.string = "status: ready"}.fork(AppClock);
~appStatus.string = "status: transcribing"}.inEnvir),
Button(view).states_([["bounce audio"]]).action_({
{~bounceAudio.value(ranSeed.value); ~appStatus.string = "status: ready"}.fork(AppClock);
~appStatus.string = "status: bouncing audio"}.inEnvir),
nil)
};
buildMetronome = {arg win;
var clock, metronome, layout;
clock = StaticText(win).string_(" 1.1").font_(Font("Liberation Mono", 200));
metronome = StaticText(win).string_([-30, -105, -104].collect({arg int; int.asAscii})
.as(String)).font_(Font("Liberation Mono", 300)).stringColor_(Color.red);
layout = HLayout(
clock,
StaticText(win).string_("|").font_(Font("Liberation Mono", 200)),
metronome
);
[clock, metronome, layout]
};
updateSection = {arg mod, clock, metronome, sectionDisplay, refresh = true, indirect = false;
var changeSection;
case
{(currentSubsection > 1) && (mod < 0)} {
currentSubsection = 1;
}
{(currentSubsection <= 1) && (mod < 0) && (currentSection > 1)} {
currentSection = currentSection + mod;
if(indirect, {
currentSubsection = ~sectionNavDict[[currentSection, 1]][1]
}, {
currentSubsection = 1;
})
}
{(mod > 0) && (~sectionNavDict[[currentSection + mod, 1]] != nil)} {
currentSection = currentSection + mod;
currentSubsection = 1;
};
if(refresh, {
updateTransport.value(clock, metronome, sectionDisplay,
~sectionNavDict[[currentSection, currentSubsection]][0], 1,
currentSection, currentSubsection
);
});
};
buildTransport = {arg win, view, clock, metronome, preampBusses, accompBusses, postampBusses;
var sec, subsec, sectionDisplay, layout, player;
sectionDisplay = StaticText(win).string_("section: 1.1").font_(Font("Liberation Mono", 70));
OSCFunc({ arg msg, time;
{
var measure, beat, section, subsection;
# measure, beat, section, subsection = msg[3..];
currentSection = sec = section.asInteger;
currentSubsection = subsec = subsection.asInteger;
updateTransport.value(clock, metronome, sectionDisplay, measure, beat, section, subsection);
}.inEnvir.defer;
},'/measureClock_' ++ ~hash, s.addr);
layout = HLayout(
Button(view).states_([["<<", Color.black]]).action_({arg pState; updateSection.value(-1, clock, metronome, sectionDisplay)}.inEnvir),
Button(view).states_([["<", Color.black]]).action_({arg pState; updateSubsection.value(-1, clock, metronome, sectionDisplay)}.inEnvir),
Button(view).states_([["play", Color.black], ["stop", Color.black, Color.grey]]).action_({arg pState;
if(pState.value == 1, {
player = {
var startMeasure = ~sectionNavDict[[currentSection, currentSubsection]][0] - 1;
~patternProxy.source = ~genPlayablePatterns.value(startMeasure, ~patterns, preampBusses, accompBusses, postampBusses);
Pbind(\instrument, \click_ ++ ~hash, \beat, Pseq([1, 2, 1, 2]), \dur, 1).play(~tempoClock, quant: 0);
[1, 2, 1, 2].do({arg beat;
{
metronome.stringColor = metronomeColorFunc.value(beat);
metronome.string = metronomeStringFunc.value(beat);
}.defer;
0.75.wait;
{metronome.string = ""}.defer;
0.25.wait;
});
~patternProxy.play(~tempoClock, quant: 0)
}.fork(~tempoClock, quant: 0)
}, {
~patternProxy.pause;
//player.stop;
updateTransport.value(clock, metronome, sectionDisplay,
~sectionNavDict[[currentSection, currentSubsection]][0], 1,
currentSection, currentSubsection);
});
}.inEnvir),
Button(view).states_([[">", Color.black]]).action_({arg pState; updateSubsection.value(1, clock, metronome, sectionDisplay)}.inEnvir),
Button(view).states_([[">>", Color.black]]).action_({arg pState; updateSection.value(1, clock, metronome, sectionDisplay)}.inEnvir), nil,
sectionDisplay, nil);
[sectionDisplay, layout]
};
buildTempoControl = {arg view;
var tempo, address, updateSection;
HLayout(
tempo = TextField(view).string_("60"),
Button(view).states_([["set tempo"]]).action_({~tempoClock.tempo = tempo.string.asInteger / 60}.inEnvir),
[StaticText(view).string_(" "), stretch: 1])
};
buildMasterFader = {arg view;
var trackIndicators, layout, volSlider, muteButton;
trackIndicators = {LevelIndicator()} ! 2;
OSCFunc.new({arg msg;
{trackIndicators[0].value = msg[3].ampdb.linlin(-50, 0, 0, 1)}.defer;
{trackIndicators[1].value = msg[4].ampdb.linlin(-50, 0, 0, 1)}.defer
}, '/masterLevels_' ++ ~hash, s.addr);
layout = HLayout([
VLayout(
HLayout(
volSlider = Slider(view).value_(0.8).action_(
{arg v; var masterVol = v.value * 1.25; ~play.set(\masterVol, masterVol)}.inEnvir),
trackIndicators[0],
trackIndicators[1]),
muteButton = Button(view).states_([["mute", Color.black], ["mute", Color.black, Color.grey]]).action_(
{arg v; var masterMute = (1 - v.value).abs; ~play.set(\masterMute, masterMute)}.inEnvir),
StaticText(view).string_("master").align_(\center)
), stretch: 2], nil);
[layout, volSlider, muteButton]
};
buildTrackFader = {arg view, name, index;
var trackIndicator, layout, volSlider, muteButton, panKnob;
trackIndicator = LevelIndicator();
OSCFunc.new({arg msg; {trackIndicator.value = msg[3].ampdb.linlin(-50, 0, 0, 1)}.defer},
'/trackLevel_' ++ index ++ "_" ++ ~hash, s.addr);
layout = HLayout(
VLayout(
HLayout(
volSlider = Slider(view).value_(0.8).action_(
{arg v; var vol = v.value * 1.25; ~play.set(\vol_ ++ index, vol)}.inEnvir),
trackIndicator),
muteButton = Button(view).states_([["mute", Color.black], ["mute", Color.black, Color.grey]]).action_(
{arg v; var mute = (1 - v.value).abs; ~play.set(\mute_ ++ index, mute)}.inEnvir).value_(0),
VLayout(
StaticText(view).string_("pan").align_(\center),
panKnob = Knob(view).action_({arg v; var pan = v.value * 2 - 1; ~play.set(\pan_ ++ index, pan)}.inEnvir).value_(0.5)
),
StaticText(view).string_(name).align_(\center)
),
nil);
[layout, volSlider, muteButton, panKnob]
};
masterView = {arg win, preampBusses, accompBusses, postampBusses;
var view, generatorLayout, clock, metronome, metronomeLayout, transportLayout, auxControlsLayout, countOff, ranSeed, order, tempo, sectionDisplay, address;
view = View(win);
generatorLayout = buildGenerator.value(view);
# clock, metronome, metronomeLayout = buildMetronome.value(win);
# sectionDisplay, transportLayout = buildTransport.value(win, view, clock, metronome, preampBusses, accompBusses, postampBusses);
auxControlsLayout = buildTempoControl.value(view);
view.layout_(
HLayout(
[
VLayout(
metronomeLayout,
[StaticText(view).string_(" "), stretch: 1],
transportLayout,
[StaticText(view).string_(" "), stretch: 1],
auxControlsLayout,
[StaticText(view).string_(" "), stretch: 1],
generatorLayout),
alignment: \top
]
)
)
};
faderView = {arg win;
var view, masterIndicators, trackIndicators, master, tracks, openButton, saveButton;
var partAbbr = ["*", "III", "II", "I", "accomp_I", "accomp_II", "click"];
var trackNames = ["*", "III", "II", "I", "accomp_I", "accomp_II", "click"];
var partVols, partMutes, partPans;
var masterMute, masterVol;
// set initial mixer values
partVols = [1, 1, 1, 1, 1, 1];
partMutes = [0, 1, 1, 1, 1, 0];
partPans = [0, 0, 0, 0, 0, 0];
masterMute = 1;
masterVol = 1;
view = View(win);
masterIndicators = {LevelIndicator()} ! 2;
trackIndicators = {LevelIndicator()} ! 6;
master = buildMasterFader.value(view);
tracks = {arg part;
buildTrackFader.value(view, trackNames[part], part);
} ! 7;
openButton = Button(view).states_([["open", Color.black]]).action_({
Dialog.openPanel({ arg path;
path.postln;
},{
"cancelled".postln;
});
});
saveButton = Button(view).states_([["save", Color.black]]).action_({
Dialog.savePanel({ arg path;
path.postln;
},{
"cancelled".postln;
});
});
view.layout_(HLayout(HLayout(master[0], nil, *tracks.slice(nil, 0)), VLayout(nil, openButton, saveButton)))
};
helpView = {arg win;
TextView(win).string_(File.readAllString(~dir +/+ "tkam_readme.scd")).editable_(false);
};
~generateGUI = {arg preampBusses, accompBusses, postampBusses;
var win, tabButtonReset, transportButton, mixerButton, helpButton, tabs;
win = Window("to kill a monarch", Rect(500, 500, 1100, 575), false).front;
tabButtonReset = {transportButton.value = 1; mixerButton.value = 1; helpButton.value = 1};
win.layout = VLayout(
HLayout(
HLayout(
[
transportButton = Button().states_([["transport", Color.white, Color.grey], ["transport", Color.black]]).action_(
{tabButtonReset.value; transportButton.value = 0; tabs.index = 0 }.inEnvir).value_(0), stretch: 1
], [
mixerButton = Button().states_([["mixer", Color.white, Color.grey], ["mixer", Color.black]]).action_(
{tabButtonReset.value; mixerButton.value = 0; tabs.index = 1 }.inEnvir).value_(1), stretch: 1
]
),
helpButton = Button().states_([["help", Color.white, Color.grey], ["help", Color.black]]).action_(
{tabButtonReset.value; helpButton.value = 0; tabs.index = 2 }.inEnvir).value_(1)
),
tabs = StackLayout(masterView.value(win, preampBusses, accompBusses, postampBusses), faderView.value(win), helpView.value(win)));
};
)