Đổi âm thanh

  Bài viết hay nhất1
HTML:


<main>
<section id="entertainment">
<div id="faces"></div>
<div id="chano"><div><div><div></div></div></div></div>
</section>
<section id="sequencer">
<div id="sequence"></div>
<nav class="controls">
<ul>
<li>
<input id="bpm" type="range" min="80" max="140" />
</li>
<li>
<button id="go">Start</button>
</li>
</ul>
</nav>
</section>
</main>



CSS:

$cols: 16;
$rows: 4;
$frame-h: 463px;
$frame-w: 300px;
$frame-count: 13;
$node-bg-di: 118px;
$row-h: $node-bg-di;
$asset-root: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/111863/";
$mobile-w: 668px;
$c-bg: #101010;
$c-primary: #D79C57;
$c-primary-d: darken($c-primary, 10%);
$c-secondary: #996888;
$c-material: #444;
$c-material-xl: lighten($c-material, 15%);
$c-material-l: lighten($c-material, 5%);
$c-material-d: darken($c-material, 5%);
$c-material-xd: darken($c-material, 10%);
$c-material-xxd: darken($c-material, 15%);
$c-border: rgba(0,0,0,0.35);
$c-border: $c-material-xxd;

html, body {
height: 100%;
min-height: 422px;
}

main {
width: 100%;
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}

section {
margin: 0 auto;
}

button {
appearance: none;
color: white;
background: $c-primary;
border: none;
border-radius: 4px;
text-shadow: -1px -1px 0px $c-primary-d;
border: 1px solid $c-primary-d;
&:hover {
background: $c-primary-d;
}
}

.mobile-start {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background: rgba(0,0,0,0.9);
button {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 2rem;
padding: 2rem 2rem;
}
}

#entertainment {
padding: 0 0 1rem 0;
width: 150px;
height: 150px;
@media (min-width: $mobile-w) {
width: 300px;
height: 300px;
}
position: relative;
#chano, #faces {
position: absolute;
}
}

#sequencer {
width: 90%;
max-width: 1200px;
padding: 0.25rem;
background: $c-material-xd;
border-radius: 4px;
box-shadow: 0px 2px 0px 2px $c-material-xxd;

ul {
border-radius: 4px;
list-style: none;
margin: 0.25rem 0 0;
padding: 0.5rem;
text-align: center;
background: $c-material-d;
border: 1px solid $c-border;
li {
display: inline-block;
margin: 0;
+ li { margin-left: 1rem; }
label {
display: block;
}
}
}
button {
box-sizing: border-box;
padding: 0.5rem 0;
}
button, input {
width: 100px;
}
}

#faces {
display: flex;
flex-wrap: wrap;
width: 100%;
position: relative;
box-sizing: border-box;
background: $c-material-xd;
box-shadow: 0px 2px 0px 2px $c-material-xxd;
border-radius: 4px;
padding: 0.5rem;

div:nth-child(1) { border-radius: 4px 0 0 0; }
div:nth-child(2) { border-radius: 0 4px 0 0; }
div:nth-child(3) { border-radius: 0 0 0 4px; }
div:nth-child(4) { border-radius: 0 0 4px 0; }

[class^="face-"] {
width: 50%;
position: relative;
cursor: pointer;
overflow: hidden;
&::before {
display: block;
content: "";
width: 100%;
padding-top: 100%;
}
&::after {
content: "";
cursor: pointer;
position: absolute;
top: 0; left: 0; bottom: 0;
width: 100%;
background-size: cover;
filter: grayscale(1);
}
&:hover::after {
filter: grayscale(0);
}
}
}

// the sequencer rows
[class^="row-"] {
width: 100%;
display: flex;
box-sizing: border-box;
border-bottom: 1px solid $c-border;
border-right: 1px solid $c-border;
border-left: 1px solid $c-border;
overflow: hidden;
transform: translateZ(0);

&:first-child {
border-top: 1px solid $c-border;
border-radius: 4px 4px 0 0;
}
&:last-child {
border-radius: 0 0 4px 4px;
}

span {
position: relative;
display: block;
box-sizing: border-box;
width: 1 / $cols * 100%;
cursor: pointer;
overflow: hidden;
background: $c-material-d;
transform: translateZ(0);

&::before {
content: "";
display: block;
width: 100%;
padding-top: 100%;
}

+ span {
border-left: 1px solid $c-border;
}

&:nth-child(n+5):not(:nth-child(n+9)),
&:nth-child(n+13) {
background: $c-material-l;
}

&::after {
content: "";
position: absolute;
top: 0; left: 0; bottom: 0;
width: 100%;
background-size: cover;
border: 1px solid $c-border;

transform-origin: 50% 50%;
@media (min-width: $mobile-w) {
transition: transform 70ms ease-in-out,
filter 70ms ease-in-out,
border-radius 100ms ease-in-out;
}
}

&[data-val="1"] {
&::after {
opacity: 0.8;
transform: scale(1.05) translateZ(0);
filter: grayscale(0);
border: none;
border-radius: 0px;
}
}
&[data-val="0"] {
&::after {
opacity: 0.6;
transform: scale(0.Cool translateZ(0);
filter: grayscale(1);
border-radius: 50%;
}
}

&:hover {
background: $c-material-xl!important;
&::after {
opacity: 1;
}
}
}
}

@for $row from 1 through $rows {
[class^="face-#{$row - 1}"]::after,
[class^="row-#{$row - 1}"] span::after {
background-image: url(#{$asset-root}chance-the-sampler-face-#{$row}.jpg);
}
}

@for $col from 1 through $cols {
#faces[class*="#{$col - 1}"] .face-#{$col - 1}::after {
background-position: -100% center;
filter: grayscale(0);
}
.current-#{$col - 1} [data-col="#{$col - 1}"] {
@media (min-width: $mobile-w) {
&, &:hover { background: rgba(255,255,255,0.4)!important; }
}
&::after {
opacity: 1!important;
}

&[data-val="1"] {
&::after {
background-position: -100% center;
}
}
}
}

#chano div {
display: none;
@media (min-width: $mobile-w) {
.box-reflect & {
display: block;
position: absolute;
transform: translate(-100%, -50%) scale(0.5) rotate(15deg);
-webkit-box-reflect: above;
}
}
}

#chano {
transform: translate(-50%, -50%);
@media (min-width: $mobile-w) {
html:not(.box-reflect) & {
display: none;
}
.box-reflect & {
transform: translate(-300px, -50%);
-webkit-box-reflect: right 300px;
}
}
}

:not(.mobile) #chano div,
#chano {
top: 50%;
left: 50%;
opacity: 0;
pointer-events: none;
transition: opacity 1000ms;
.playing & { opacity: 1; }
&::after {
content: "";
display: block;
background-image: url("#{$asset-root}chance-the-sprite.png");
height: $frame-h / 4;
width: $frame-w / 4;
background-size: ($frame-w/4) * $frame-count ($frame-h/4);
@media (min-width: $mobile-w) {
height: $frame-h / 2;
width: $frame-w / 2;
background-size: ($frame-w/2) * $frame-count ($frame-h/2);
}
}
}
@for $i from 1 through $frame-count {
#chano.frame-#{$i} div::after,
#chano.frame-#{$i}::after {
$x: ($i - 1) / ($frame-count) * ($frame-w / 4 * -$frame-count);
background-position: $x center;
@media (min-width: $mobile-w) {
$x: ($i - 1) / ($frame-count) * ($frame-w / 2 * -$frame-count);
background-position: $x center;
}
}
}

body {
color: white;
background: $c-bg;
// overflow: hidden;
&::before {
content: "";
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background-size: cover;
background-position: center;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/111863/chance-the-sampler-bg.jpg);
opacity: 0.1;
filter: grayscale(1);
}

.box-reflect &.playing::before {
animation: bg 1s ease-in-out alternate infinite;
}
}

@for $i from 80 through 140 {
html.bpm-#{$i}.box-reflect body::before {
animation-duration: (1 / ($i / 60)) * 1s;
}
}

@keyframes bg {
from { transform: scale(1); }
to { transform: scale(1.05); }
}


JS:

console.clear();

/********************
Instantiate Chano
********************/

var chance = new Chano({
bpm: 90,
beats: 16,
selectors: {
bpm: "#bpm",
go: "#go"
}
});

chance.load.then(function(chano) {
http://chano.play();
var sequence = new Sequence({
sequence: "#sequence",
faces: "#faces",
chano: chano
});

var animation = new Animation({
chano: "#chano",
frames: 13
});

chano.update = function(time, col) {
sequence.$seq.className = "current-" + col;
sequence.$faces.className = "current-" + chano.actives.join("");
setTimeout(function() {
sequence.$faces.className = "";
}, 100 / chano.bpm * 64);
animation.update();
};
});

/********************
Chance the Sampler: Player
********************/

function Chano(params) {
var C = {};

init();

return C;

/***********
initializer
***********/

function init() {
drawPlaceholder(); // better screengrab
setParams();

/*********
instance.load.then(function(chano) {
// do whatever with chano
});
*********/
C.is_mobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
C.click_event = C.is_mobile ? "touchstart" : "click";
if("-webkit-box-reflect" in document.body.style) {
document.querySelector("html").className += "box-reflect ";
}

C.load = new Promise(function(resolve, reject) {
// if mobile, this needs to be instantiated by a click.
setMobile(go);

function go() {
var set_synth = setSynth();
set_synth.then(function() {
removePlaceholder();
setDomValue();
setMethods();
setMatrix();
setTransport();
setEvents();
resolve(C);
});
}
});
}

/***********
placeholder
***********/

function drawPlaceholder() {
C.placeholder = document.createElement("div");
C.placeholder.style.backgroundImage = "url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/111863/chance-the-sampler-screen.png')";
C.placeholder.style.backgroundPosition = "center";
C.placeholder.style.backgroundSize = "cover";
C.placeholder.style.position = "fixed";
C.placeholder.style.top = 0;
C.placeholder.style.left = 0;
C.placeholder.style.right = 0;
C.placeholder.style.bottom = 0;
document.body.appendChild(C.placeholder);
}

function removePlaceholder() {
C.placeholder.remove();
}

/***********
setters
***********/

function setMobile(callback) {
// if mobile, we need to instantiate with a click
if(C.is_mobile) {
document.querySelector("html").className += "mobile ";
var $element = document.createElement("div");
$element.className = "mobile-start";
document.body.appendChild($element);
var $mobile_start = document.createElement("button");
$mobile_start.innerHTML = "Launch";
$mobile_start.addEventListener("touchend", function(e) {
e.preventDefault();
Tone.startMobile();
$element.remove();
callback();
});
$element.appendChild($mobile_start);
} else {
callback();
}
}

function setParams() {
C._set = {
bpm: params.bpm || 90,
beats: params.beats || 16
}
C._el = {
$bpm: document.querySelector(params.selectors.bpm),
$go: document.querySelector(params.selectors.go)
}
}

function setDomValue() {
C._el.$bpm.value = C._set.bpm;
}

function setSynth() {
return new Promise(function(resolve, reject) {
var root = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/111863/chance-the-sampler-";
C.keys = new Tone.PolySynth(4, Tone.Sampler, {
sd1: root + "01.mp3",
hh1: root + "02.mp3",
sd2: root + "03.mp3",
kd1: root + "04.mp3",
}, {
"volume" : -5,
}).toMaster();
C.note_names = ["sd1", "hh1", "sd2", "kd1"];

var count = 4;
var loaded = 1;
for(var i = 0; i < count; i++) {
var buffer = new Tone.Buffer(root + "0" + (i+1) + ".mp3", function(){
loaded++;
if(loaded === count) {
resolve("Audios Loaded");
}
});
}
});
}

function setMatrix() {
C.matrix = [
[1,0,0,1],
[0,0,0,0],
[1,0,0,0],
[0,0,0,0],

[1,1,0,0],
[0,1,0,1],
[1,1,0,0],
[0,0,0,0],

[0,0,0,1],
[1,0,1,0],
[0,0,0,1],
[1,0,0,0],

[0,0,0,0],
[1,0,1,0],
[0,0,0,1],
[1,0,1,0]
];
}

function setTransport() {
var arr = [];
for(var i = 0; i < C._set.beats; i++) arr.push(i);
C.loop = new Tone.Sequence(function(time, col) {
C.actives = [];
var column = C.matrix[col];
for (var i = 0; i < 4; i++) {
if (column[i] === 1) {
C.actives.push(i);
C.keys.triggerAttackRelease(C.note_names[i], "8n", time);
}
}
C.update(time, col);
}, arr, "16n");
C.updateBpm(C._set.bpm);
Tone.Transport.start();
}

function setMethods() {
C.updateBpm = updateBpm;
C.updateMatrix = updateMatrix;
C.play = play;
C.pause = pause;
// provide update function
C.update = function(time, col) {};
}

function setEvents() {
C._el.$bpm.addEventListener("change", function(e) {
C.updateBpm(e.target.value);
});
C._el.$go.addEventListener(C.click_event, togglePlay);
}


/***********
events
***********/

function updateMatrix(col, row, value) {
C.matrix[col][row] = value;
}

function updateBpm(bpm) {
Tone.Transport.bpm.value = bpm;
var $html = document.querySelector("html");
var bpm_class = $html.className.match("bpm-");
$html.className = bpm_class ? $html.className.replace(/bpm-\d+/g,"bpm-"+bpm) : $html.className + "bpm-" + bpm;
C.bpm = bpm;
}

function play() {
C.loop.start();
document.body.className = "playing";
C.playing = true;
}

function pause() {
C.loop.stop();
document.body.className = "";
C.playing = false;
}

function togglePlay(e) {
if(C.playing) {
C.pause();
if(e && e.target) e.target.innerHTML = "Start";
} else {
C.play();
if(e && e.target) e.target.innerHTML = "Stop";
}
}

}

/********************
Chance the Sampler: Sequencer
********************/

function Sequence(params) {
var S = {};

init();

return S;

/***********
initializer
***********/

function init() {
setData();
createElements();
}

/***********
private
***********/

function setData() {
S.chano = params.chano;
S.$seq = document.querySelector(params.sequence);
S.$faces = document.querySelector(params.faces);
}

function createElements() {
S.nodes = [];
S.rows = [];
for(var r = 0; r < S.chano.matrix[0].length; r++) {
S.nodes.push([]);
var $row = document.createElement("div");
$row.className = "row-" + r;
S.$seq.appendChild($row);
S.rows.push($row);
}

for(var r = 0; r < S.chano.matrix[0].length; r++) {
var $face = document.createElement("div");
$face.className = "face-" + r;
$face.setAttribute("data-key", r);
S.$faces.appendChild($face);
$face.addEventListener(S.chano.click_event, function(e) {
var el = e.target;
var key = parseInt(el.getAttribute("data-key"));
S.$faces.className = "face-" + key;
if(!S.chano.playing) {
setTimeout(function() {
S.$faces.className = "";
}, 100);
}
var note = S.chano.note_names[key];
S.chano.keys.triggerAttackRelease(note, "8n");
});
}

for(var c = 0; c < S.chano.matrix.length; c++) {
var col = S.chano.matrix[c];

for(var r = 0; r < col.length; r++) {
var el = document.createElement("span");
el.setAttribute("data-row", r);
el.setAttribute("data-col", c);
el.setAttribute("data-val", col[r]);
el.addEventListener(S.chano.click_event, handleNodeClick);
S.nodes[r].push(el);
S.rows[r].appendChild(el);
}
}
}

function handleNodeClick(e) {
var el = e.target,
col = el.getAttribute("data-col"),
row = el.getAttribute("data-row"),
val = el.getAttribute("data-val");
val = val === "1" ? 0 : 1;
el.setAttribute("data-val", val);
S.chano.updateMatrix(col, row, val);
}


}


/********************
Chance the Sampler: Sprite Animation
********************/

function Animation(params) {
var A = {};

init();

return A;

/***********
initialize
***********/

function init() {
setData();
setUpdate();
}

/***********
private
***********/

function setData() {
A.frame = 1;
A.direction = "up";
A.max_frame = params.frames;
A.$chano = document.querySelector(params.chano);
}

function setUpdate() {
A.update = function() {
A.$chano.className = "frame-" + A.frame;
if(A.frame === 1) {
A.direction = "up";
A.frame++;
} else if(A.frame === A.max_frame) {
A.direction = "down";
A.frame--;
} else if(A.direction === "up") {
A.frame++;
} else {
A.frame--;
}
}
}
}


Bạn không có quyền trả lời bài viết