sound-mixing-bowl/public/conductor/index.js
Dooho Yi 1ac0dcd868 bug fix
next button deactivate @ last page.
2018-09-16 04:09:48 +09:00

841 lines
25 KiB
JavaScript

//paperscript (paperjs)
//'index' page
$(document).ready(function() {
//common metrics
var vs = view.size;
var vsw = vs.width;
var vsh = vs.height;
var vss = view.size / 10;
var vssw = vss.width;
var vssh = vss.height;
//pre-load resources
Promise.all([
//imgs
RasterImport_size1('./imgs/phonehand.png'),
SVGImport_size1('./imgs/arrow-circle-right.svg'),
SVGImport_size1('./imgs/arrow-circle-left.svg'),
SVGImport_size1('./imgs/hand-point-right-regular.svg'),
SVGImport_size1('./imgs/listen-icon.svg'),
SVGImport_size1('./imgs/iconmonstr-plus-4.svg'),
SVGImport_size1('./imgs/iconmonstr-minus-4.svg'),
//clap
AudioImport_p5("./audio/clap@2/" + ("0" + getRandomInt(1, 2)).slice(-2) + ".mp3"),
//btn_sounds ==> 9
AudioImport_p5("./audio/bridgeA/고향돌리도.mp3"),
AudioImport_p5("./audio/bridgeA/동물소리흉내.mp3"),
// AudioImport_p5("./audio/bridgeA/동물소리흉내02.mp3"),
AudioImport_p5("./audio/bridgeA/동물소리흉내03.mp3"),
AudioImport_p5("./audio/bridgeA/모래야돌아와.mp3"),
AudioImport_p5("./audio/bridgeA/물소리가있었다.mp3"),
AudioImport_p5("./audio/bridgeA/우와.mp3"),
AudioImport_p5("./audio/bridgeA/이거물에넣고해도되요.mp3"),
AudioImport_p5("./audio/bridgeA/흰수마자돌아와.mp3"),
AudioImport_p5("./audio/bridgeA/흰수마자어디갔니.mp3"),
//set_sounds ==> 8
AudioImport_p5("./audio/path/가을아침.mp3"),
AudioImport_p5("./audio/path/내나이.mp3"),
AudioImport_p5("./audio/path/노래.mp3"),
AudioImport_p5("./audio/path/사랑을했따.mp3"),
AudioImport_p5("./audio/path/아아아아.mp3"),
AudioImport_p5("./audio/path/하모니카.mp3"),
AudioImport_p5("./audio/path/합주.mp3"),
AudioImport_p5("./audio/path/휘파람.mp3"),
//beach_sounds ==> 8
AudioImport("./audio/beach/두드리는01.mp3"),
AudioImport("./audio/beach/두드리는02.mp3"),
// AudioImport("./audio/beach/두드리는03.mp3"),
// AudioImport("./audio/beach/두드리는04.mp3"),
AudioImport("./audio/beach/두드리는06.mp3"),
// AudioImport("./audio/beach/모래걸음.mp3"),
AudioImport("./audio/beach/물소리.mp3"),
AudioImport("./audio/beach/물장구.mp3"),
AudioImport("./audio/beach/손장구.mp3"),
AudioImport("./audio/beach/운더강강술래.mp3"),
// AudioImport("./audio/beach/웃음.mp3"),
AudioImport("./audio/beach/젖은모래쓸어내기.mp3"),
// AudioImport("./audio/beach/천막긁는.mp3"),
// AudioImport("./audio/beach/풍덩.mp3"),
//
]).then(function(imports) {
//imgs
var phonehand = imports[0];
var anext = imports[1];
var aprev = imports[2];
var hand = imports[3];
var iconsound = imports[4];
var plus = imports[5];
var minus = imports[6];
//clap
var clap = imports[7];
//groups
var group_names = [
'너',
'곰곰',
'레나',
'은솔',
];
var group_keys = [
'grp1',
'grp2',
'grp3',
'grp4',
];
//buttons
var btn_names = [
'고향',
'동물1',
'동물2',
'모래',
'물소리',
'우와',
'이거',
'돌아와',
'어디'
];
var btn_sounds = [
imports[8],
imports[9],
imports[10],
imports[11],
imports[12],
imports[13],
imports[14],
imports[15],
imports[16],
];
//set list
var set_sounds = {
'가을아침': imports[17],
'내나이': imports[18],
'노래': imports[19],
'사랑': imports[20],
'아아': imports[21],
'하모니카': imports[22],
'합주': imports[23],
'휘파람': imports[24]
};
//beach list
var beach_sounds = {
'두드림1': imports[25],
'두드림2': imports[26],
'두드림6': imports[27],
'물소리': imports[28],
'물장구': imports[29],
'손장구': imports[30],
'강강': imports[31],
'모래': imports[32]
};
var beach_players = {
'두드림1': [],
'두드림2': [],
'두드림6': [],
'물소리': [],
'물장구': [],
'손장구': [],
'강강': [],
'모래': [],
};
//screen changer
var nscreen = 6;
var screens = [];
var screen_names = {};
screen_names['start'] = 1;
screen_names['select'] = 2;
screen_names['check'] = 3;
screen_names['bridgeA'] = 4;
screen_names['path'] = 5;
screen_names['beach'] = 6;
var curscreen;
for (var idx = 0; idx < nscreen; idx++) {
screens.push(new Layer());
}
function changeScreen(page) {
//pagination buttons
aprev._activate();
anext._activate();
//
if (page < 1) page = 1;
if (page > nscreen) page = nscreen;
curscreen = page;
for (var idx = 0; idx < nscreen; idx++) {
//
if (idx == page - 1) {
screens[idx].bringToFront();
top.bringToFront();
$('.objstring').eq(idx).css('z-index', 1);
//
screens[idx].activate();
} else {
screens[idx].sendToBack();
$('.objstring').eq(idx).css('z-index', -1);
}
}
//pagination buttons
if (curscreen == 1) {
aprev._deactivate();
}
if (curscreen == 2) {
anext._deactivate();
}
if (curscreen == nscreen) {
anext._deactivate();
}
}
function nextScreen() {
if (curscreen + 1 <= nscreen) {
curscreen++;
changeScreen(curscreen);
}
}
function prevScreen() {
if (curscreen - 1 > 0) {
curscreen--;
changeScreen(curscreen);
}
}
function changeScreenByName(pagename) {
changeScreen(screen_names[pagename]);
}
function getScreenNameNext() {
if (curscreen + 1 <= nscreen) {
return Object.keys(screen_names)[curscreen + 1 - 1];
} else {
return Object.keys(screen_names)[curscreen - 1];
}
}
function getScreenNamePrev() {
if (curscreen - 1 > 0) {
return Object.keys(screen_names)[curscreen - 1 - 1];
} else {
return Object.keys(screen_names)[curscreen - 1];
}
}
//top layer
var top = new Layer(); // new Layer() will be automatically activated at the moment.
//networking - socket.io
//var socket = io('http://192.168.1.105:8080');
var socket = io('http://choir.run:8080');
//net. connection marker
var netstat = new Path.Circle({
center: view.bounds.topRight + [-vssw / 2, +vssw / 2],
radius: vssw / 4,
fillColor: 'hotpink',
strokeWidth: 2,
strokeColor: 'gray',
dashArray: [4, 4],
onFrame: function(event) {
this.rotate(1);
}
});
netstat.fillColor.alpha = 0;
//
socket.on('connect', function() {
console.log("i' m connected!");
top.activate();
netstat.fillColor.alpha = 1;
socket.on('disconnect', function() {
console.log("i' m disconnected!");
top.activate();
netstat.fillColor.alpha = 0;
});
});
//page change - prev. page
aprev.addTo(project);
aprev.scale(vsw / 4);
aprev.position = [0, 0]; //reset position, before relative positioning !!
aprev.translate([vssw, vssw * 2.5]);
aprev.fillColor = 'pink';
aprev._socket = socket;
aprev._isactive = false;
aprev._activate = function() {
this._isactive = true;
this.opacity = 1;
}
aprev._deactivate = function() {
this._isactive = false;
this.opacity = 0.3;
}
aprev.onClick = function() {
if (this._isactive == true) {
prevScreen();
}
};
//page change - next. page
anext.addTo(project);
anext.scale(vsw / 4);
anext.position = [0, 0]; //reset position, before relative positioning !!
anext.translate([vssw * 9, vssw * 2.5]);
anext.fillColor = 'pink';
anext._socket = socket;
anext._isactive = false;
anext._activate = function() {
this._isactive = true;
this.opacity = 1;
}
anext._deactivate = function() {
this._isactive = false;
this.opacity = 0.3;
}
anext.onClick = function() {
if (this._isactive == true) {
nextScreen();
}
};
//title background
new Path.Rectangle({
point: [vssw * 2, vssw * 1.5],
size: [vssw * 6, vssw * 2],
fillColor: 'white',
radius: 30,
}).opacity = 0.3;
//screen #1 - 'home'
changeScreen(1);
new Path.Rectangle([0, 0], vs).fillColor = '#999';
//hello, screen.
phonehand.addTo(project);
phonehand.scale(vsw / 1.5);
phonehand.position = view.center;
//phonehand.position.y -= vssh;
//screen #2 - 'select'
changeScreen(2);
new Path.Rectangle([0, 0], vs).fillColor = '#3333ff'; //;
//group select buttons
var group_selected = undefined; //key
for (var row = 0; row < 2; row++) {
for (var col = 0; col < 2; col++) {
var idx = row * 2 + col;
var c = new Path.Circle({
center: [col * vssw * 3 + vssw * 3, row * vssw * 3 + vssw * 6],
radius: vssw * 0.8,
fillColor: new Color({
hue: getRandom(0, 180),
saturation: 1,
brightness: 1
}),
_idx: idx,
onClick: function() {
group_selected = group_keys[this._idx];
console.log(group_selected);
//next screen.
changeScreen(3);
}
});
new PointText({
point: c.bounds.topLeft + [0, -5],
content: group_names[idx],
fontSize: '1em',
fontWeight: 'bold',
fillColor: c.fillColor
});
}
}
//screen #3 - check
changeScreen(3);
new Path.Rectangle([0, 0], vs).fillColor = '#393';
//TODO: info text.
new PointText({
content: "네트워크 테스트!",
point: view.center + [-vssw * 3, -vssw * 2],
fontWeight: 'bold',
fontSize: '2em',
fillColor: 'gold'
});
new PointText({
content: "사운드 테스트!",
point: view.center + [-vssw * 3, vssw * 0],
fontWeight: 'bold',
fontSize: '2em',
fillColor: 'pink'
});
new PointText({
content: "동그라미 터치!",
point: view.center + [-vssw * 3, vssw * 2],
fontWeight: 'bold',
fontSize: '2em',
fillColor: 'red'
});
new Path.Circle({
center: view.center,
radius: vsw / 4,
fillColor: 'white',
opacity: 0.5,
onClick: function() {
clap.play();
}
});
//screen #4 - bridgeA
changeScreen(4);
new Path.Rectangle([0, 0], vs).fillColor = '#333';
//sound list
var buttons = [];
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var idx = row * 3 + col;
//play/stop button (networked between groups)
var c = new Group([
new Path.Circle({
center: [col * vssw * 2.5 + vssw * 2, row * vssw * 2.3 + vssw * 5.5],
radius: vssw * 0.8,
fillColor: new Color({
hue: getRandom(0, 180),
saturation: 1,
brightness: 1
}),
_socket: socket,
_key: btn_names[idx],
_player: btn_sounds[idx],
_playcount: 0,
_init: function() {
var that = this;
this._socket.on('sound', function(msg) {
if (msg.group == group_selected && msg.name == that._key) {
if (msg.action == 'start') {
that._playstart();
that._playcount++;
}
}
});
this.nextSibling.opacity = 0; //marker off!
this._player.playMode('restart');
},
_playstart: function() {
// play (re-)start now!
this._player.play();
this.nextSibling.opacity = 1; //marker on!
var that = this;
this._player.onended(function() {
if (that._playcount > 0) {
that._playcount--;
if (that._playcount == 0) { // only do this, when it is finally stopped.
that.nextSibling.opacity = 0; //marker off!
}
}
});
},
_playstop: function() {
this._player.stop();
this.nextSibling.opacity = 0; //marker off!
},
onMouseDown: function() {
//
this._playstart();
this._playcount++;
//
this._socket.emit('sound', {
name: this._key,
action: 'start',
group: group_selected
});
}
}),
//the marking ring around the button
new Path.Circle({
center: [col * vssw * 2.5 + vssw * 2, row * vssw * 2.3 + vssw * 5.5],
radius: vssw * 1,
strokeWidth: 5,
strokeColor: 'white'
})
]);
c.firstChild._init();
buttons.push(c);
//labels
new PointText({
point: c.firstChild.bounds.topLeft + [0, -5],
content: btn_names[idx],
fontSize: '2em',
fontWeight: 'bold',
fillColor: c.firstChild.fillColor
});
}
}
//speed controller - frame
new Group({
children: [
new Path.Rectangle({
point: [vsw - vssw * 1.5, vssh * 2.5],
size: [vssw, vssh * 6],
radius: 20,
}),
new Path.Rectangle({
point: [vsw - vssw * 1.5, vssh * 2.5],
size: [vssw, vssh * 3],
fillColor: 'blue'
}),
new Path.Rectangle({
point: [vsw - vssw * 1.5, vssh * 2.5 + vssh * 3],
size: [vssw, vssh * 3],
fillColor: 'gold'
}),
],
clipped: true
});
//speed controller - knob
var knob = new Path.Circle({
center: [vsw - vssw, vssh * 2.5 + vssw * 0.5],
radius: 20,
fillColor: 'white',
_start_y: vssh * 2.5 + vssw * 0.5,
_end_y: vssh * 2.5 + vssh * 6 - vssw * 0.5,
onMouseDrag: function(event) {
if (event.point.y > this._end_y) {
this.position.y = this._end_y;
} else if (event.point.y < this._start_y) {
this.position.y = this._start_y;
} else {
this.position.y = event.point.y;
}
var control = map(this.position.y, [this._start_y, this._end_y], [-1, 1]);
//playback speed change.. (perform the effect)
buttons.forEach(function(item) {
item.firstChild._player.rate(Math.pow(5, control));
});
}
});
//initial position of the knob. 0 means 1 (Math.pow(XXX, 0) == 1)
knob.position.y = map(0, [-1, 1], [knob._start_y, knob._end_y]);
//stop button
var stopbtn = new Group({
_socket: socket,
children: [
new Path.Circle({
center: [vssw * 2.7 + vssw * 2, 2.5 * vssw * 2.7 + vssw * 6],
radius: vssw * 0.8
})
],
onMouseDown: function() {
buttons.forEach(function(item) {
item.firstChild._playstop();
item.firstChild._playcount = 0;
});
//
this._socket.emit('sound', {
name: 'stop',
action: 'stop',
group: group_selected
});
}
});
//label
stopbtn.addChild(new PointText({
point: stopbtn.bounds.topLeft + [0, -5],
content: 'stop',
fontSize: '2em',
fontWeight: 'bold'
}));
stopbtn.fillColor = 'red';
//'stop' handler
socket.on('sound', function(msg) {
if (msg.action == 'stop') {
buttons.forEach(function(item) {
item.firstChild._playstop();
item.firstChild._playcount = 0;
});
}
});
//screen #5 - path
changeScreen(5);
new Path.Rectangle([0, 0], vs).fillColor = '#333';
//
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 1; col++) {
var idx = row * 1 + col;
//play/stop/marker button (networked between groups)
var c = new Group({
children: [
//play button
new Path.Rectangle({
point: [vssw * 1.4, row * vssw * 1.5 + vssw * 4.5],
radius: vssw * 0.4,
size: [vssw * 2.8, vssw * 0.8],
fillColor: new Color({
hue: getRandom(20, 60),
saturation: 1,
brightness: 1
}),
onMouseDown: function() {
var par = this.parent;
par._player.play();
par._playcount++;
par.lastChild.fillColor = 'white'; //marker on!
par._player.onended(function() {
if (par._playcount > 0) {
par._playcount--;
if (par._playcount == 0) { // only do this, when it is finally stopped.
par.lastChild.fillColor = 'black'; //marker off!
}
}
});
//
par._socket.emit('sound', {
name: par._key,
action: 'start',
group: 'path'
});
}
}),
//stop button
new Path.Rectangle({
point: [vssw * 4.8, row * vssw * 1.5 + vssw * 4.5],
radius: vssw * 0.4,
size: [vssw * 2.8, vssw * 0.8],
fillColor: new Color({
hue: getRandom(120, 250),
saturation: 1,
brightness: 1
}),
onMouseDown: function() {
var par = this.parent;
par._player.stop();
par._playcount = 0;
par.lastChild.fillColor = 'black'; //marker off!
//
par._socket.emit('sound', {
name: par._key,
action: 'stop',
group: 'path'
});
}
}),
//playing marker
new Path.Circle({
center: [vssw * 8.5, row * vssw * 1.5 + vssw * 4.9],
radius: vssw * 0.4,
fillColor: 'black'
})
],
_socket: socket,
_key: Object.keys(set_sounds)[idx],
_player: set_sounds[Object.keys(set_sounds)[idx]],
_playcount: 0,
_init: function() {
this._player.playMode('restart');
}
});
c._init();
//label
new PointText({
point: c.firstChild.bounds.topLeft + [0, -5],
content: Object.keys(set_sounds)[idx],
fontSize: '1em',
fontWeight: 'bold',
fillColor: 'white'
});
}
}
//screen #6 - beach
changeScreen(6);
new Path.Rectangle([0, 0], vs).fillColor = '#333';
//
for (var row = 0; row < 8; row++) {
for (var col = 0; col < 1; col++) {
var idx = row * 1 + col;
//play/stop/playcount/faster/slower button (networked between groups)
var c = new Group({
children: [
//play button
new Path.Rectangle({
point: [vssw * 0.8, row * vssw * 1.5 + vssw * 4.5],
radius: vssw * 0.4,
size: [vssw * 1.6, vssw * 0.8],
fillColor: new Color({
hue: getRandom(20, 60),
saturation: 1,
brightness: 1
}),
onMouseDown: function(event) {
var par = this.parent;
par._players.push(par._player.start()._source); // start playbacks and collect their '_source's..
par._playcount++;
par.children.playcounter.content = '' + par._playcount;
//
par._socket.emit('sound', {
name: par._key,
action: 'start',
group: 'beach'
});
}
}),
//stop button
new Path.Rectangle({
point: [vssw * 2.8, row * vssw * 1.5 + vssw * 4.5],
radius: vssw * 0.4,
size: [vssw * 1.6, vssw * 0.8],
fillColor: new Color({
hue: getRandom(120, 250),
saturation: 1,
brightness: 1
}),
onMouseDown: function() {
var par = this.parent;
if (par._players.length > 0) {
(par._players.shift()).stop();
par._playcount--;
par.children.playcounter.content = '' + par._playcount;
}
//
par._socket.emit('sound', {
name: par._key,
action: 'stop',
group: 'beach'
});
}
}),
//playcounter
new PointText({
name: 'playcounter',
content: '' + 0,
point: [vssw * 4.8, row * vssw * 1.5 + vssw * 4.5 + vssw * 0.7],
fillColor: 'white',
fontSize: '2em',
fontWeight: 'bold'
}),
//faster button
new Path.Rectangle({
point: [vssw * 5.8, row * vssw * 1.5 + vssw * 4.5],
radius: vssw * 0.4,
size: [vssw * 1.6, vssw * 0.8],
fillColor: new Color({
hue: getRandom(20, 60),
saturation: 1,
brightness: 1
}),
onMouseDown: function() {
var par = this.parent;
if (par._players.length > 0) {
par._players[par._players.length - 1].playbackRate.value += 0.2;
}
//
par._socket.emit('sound', {
name: par._key,
action: 'faster',
group: 'beach'
});
}
}),
//slower button
new Path.Rectangle({
point: [vssw * 7.8, row * vssw * 1.5 + vssw * 4.5],
radius: vssw * 0.4,
size: [vssw * 1.6, vssw * 0.8],
fillColor: new Color({
hue: getRandom(120, 250),
saturation: 1,
brightness: 1
}),
onMouseDown: function() {
var par = this.parent;
if (par._players.length > 0) {
par._players[par._players.length - 1].playbackRate.value -= 0.2;
}
//
par._socket.emit('sound', {
name: par._key,
action: 'slower',
group: 'beach'
});
}
})
],
_socket: socket,
_key: Object.keys(beach_sounds)[idx],
_player: beach_sounds[Object.keys(beach_sounds)[idx]],
_players: beach_players[Object.keys(beach_players)[idx]],
_playcount: 0,
_init: function() {
this._player.loop = true;
this._player.retrigger = true;
//socket io event handling..
var that = this;
this._socket.on('sound', function(msg) {
if (msg.group == 'beach' && msg.name == that._key) {
if (msg.action == 'start') {
that._players.push(that._player.start()._source); // start playbacks and collect their '_source's..
that._playcount++;
that.children.playcounter.content = '' + that._playcount;
} else if (msg.action == 'stop') {
if (that._players.length > 0) {
(that._players.shift()).stop();
that._playcount--;
that.children.playcounter.content = '' + that._playcount;
}
} else if (msg.action == 'faster') {
if (that._players.length > 0) {
that._players[that._players.length - 1].playbackRate.value += 0.2;
}
} else if (msg.action == 'slower') {
if (that._players.length > 0) {
that._players[that._players.length - 1].playbackRate.value -= 0.2;
}
}
}
});
}
});
c._init();
//label
new PointText({
point: c.firstChild.bounds.topLeft + [0, -5],
content: Object.keys(beach_sounds)[idx],
fontSize: '1em',
fontWeight: 'bold',
fillColor: 'white'
});
}
}
//home
changeScreen(1);
//reveal the curtain.
$('#page-loading').css('z-index', -1);
//network event handlers
//event: 'sound'
socket.on('sound', function(sound) {
if (sound.name == 'clap') {
if (sound.action == 'start') {
clap.start();
}
}
});
});
});