piano.php
Quell Code
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<style>
#alles{
margin:0;
text-align:center;
font-size:20px;
font-family:Arial;
transform:scale(0.6);
margin-left:-10%;
}
h1{
text-align:center;
}
@charset "UTF-8";
* {
padding: 0;
margin: 0;
}
.pressed {
transform: rotateX(-10deg);
}
.pressed-black {
-webkit-transform: rotateX(-10deg) translateZ(-150px) !important;
transform: rotateX(-10deg) translateZ(-150px) !important;
margin-top: -20px !important;
}
.piano {
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-perspective: 1500;
perspective: 1500;
position:relative;
width: 100%;
height: 10px;
top:110px;
left: 0;
right: 0;
bottom: 0;
margin: auto;
-webkit-transform: translateZ(10px) rotateY(0deg) rotateX(-50deg);
transform: translateZ(10px) rotateY(0deg) rotateX(-50deg);
}
.white-key-group {
z-index: 1;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
width: 60px;
height: 70px;
position: absolute;
-webkit-transform-origin: 0% 0% -400px;
transform-origin: 0% 0% -400px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transition: .2s;
transition: .2s;
}
.white-key-group .size-lr {
width: 400px;
height: 70px;
}
.white-key-group .size-t {
width: 60px;
height: 400px;
}
.white-key-group .tec {
position: absolute;
top: 0;
left: 0;
-webkit-transform-origin: 0% 0%;
transform-origin: 0% 0%;
border: 1px solid #ccc;
}
.white-key-group .y90-left {
-webkit-transform: rotateY(90deg);
transform: rotateY(90deg);
background: #999;
background-image: -webkit-gradient(linear, left top, right bottom, from(#fff), to(#999));
background-image: linear-gradient(to bottom right, #fff, #999);
}
.white-key-group .y90-right {
-webkit-transform: rotateY(90deg);
transform: rotateY(90deg);
left: 0px;
background: #999;
background-image: -webkit-gradient(linear, left top, right bottom, from(#fff), to(#999));
background-image: linear-gradient(to bottom right, #fff, #999);
}
.white-key-group .x90-top {
-webkit-transform: rotateX(-90deg);
transform: rotateX(-90deg);
background: #fff;
background-image: -webkit-gradient(linear, left top, right bottom, from(#eee), to(#fff));
background-image: linear-gradient(to bottom right, #eee, #fff);
}
.white-key-group .x90-front {
-webkit-transform: rotateX(0deg);
transform: rotateX(0deg);
width: 60px;
height: 70px;
background: #eee;
background-image: -webkit-gradient(linear, top bottom, from(#fff), to(#eee));
background-image: linear-gradient(to top bottom, #fff, #eee);
position: relative;
}
.white-key-group .x90-front2 {
-webkit-transform: rotateY(0deg);
transform: rotateY(0deg);
margin-left: 60px;
width: 60px;
height: 70px;
background: #eee;
background-image: -webkit-gradient(linear, left top, right bottom, from(#999), to(#eee));
background-image: linear-gradient(to bottom right, #999, #eee);
}
.black-key-group {
margin-top: -42px;
-webkit-transform: translateZ(-150px);
transform: translateZ(-150px);
z-index: 100;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
width: 10px;
height: 10px;
position: absolute;
-webkit-transform-origin: 0% 0% -250px;
transform-origin: 0% 0% -250px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transition: .2s;
transition: .2s;
}
.black-key-group .size-lr {
width: 250px;
height: 40px;
}
.black-key-group .size-t {
width: 30px;
height: 250px;
}
.black-key-group .tec {
position: absolute;
top: 0;
left: 0;
-webkit-transform-origin: 0% 0%;
transform-origin: 0% 0%;
border: 1px solid #222;
}
.black-key-group .y90-left {
-webkit-transform: rotateY(90deg);
transform: rotateY(90deg);
background: #222;
background-image: -webkit-gradient(linear, left top, right bottom, from(#111), to(#222));
background-image: linear-gradient(to bottom right, #111, #222);
}
.black-key-group .y90-right {
-webkit-transform: rotateY(90deg);
transform: rotateY(90deg);
left: 30px;
background: #222;
background-image: -webkit-gradient(linear, left top, right bottom, from(#111), to(#222));
background-image: linear-gradient(to bottom right, #111, #222);
}
.black-key-group .x90-top {
-webkit-transform: rotateX(-90deg);
transform: rotateX(-90deg);
background: #111;
background-image: -webkit-gradient(linear, left top, right bottom, from(#333), to(#111));
background-image: linear-gradient(to bottom right, #333, #111);
}
.black-key-group .x90-front {
-webkit-transform: rotateX(0deg);
transform: rotateX(0deg);
width: 30px;
height: 40px;
background: #333;
background-image: -webkit-gradient(linear, top bottom, from(#111), to(#333));
background-image: linear-gradient(to top bottom, #111, #333);
position: relative;
}
.black-key-group .x90-front2 {
-webkit-transform: rotateY(0deg);
transform: rotateY(0deg);
margin-left: 30px;
width: 30px;
height: 40px;
background: #333;
background-image: -webkit-gradient(linear, left top, right bottom, from(#222), to(#333));
background-image: linear-gradient(to bottom right, #222, #333);
}
.black-key-group .f-notes {
color: #eee;
top: 5%;
}
.black-key-group .f-keymap {
color: #eee;
bottom: 5%;
}
.scene {
position: absolute;
width: 1200px;
height: 0px;
top:600px;
left: -5%;
right: 0;
bottom: 0;
margin: auto;
}
.menu1 {
position:absolute;
background:red;
top: 20px;
width:120%;
height: 100vh;
background: #191426;
text-align: center;
color: #C1B8B7;
font-size: 14px;
line-height: 70px;
}
.menu1 .options {
border-left: 1px solid #2f2647;
float: right;
height: 70px;
line-height: 70px;
}
.menu1 label {
margin: 0 15px;
vertical-align: middle;
padding-top: 3px;
line-height: 20px;
}
.animate {
-webkit-animation-name: expand;
animation-name: expand;
-webkit-animation-duration: 10s;
animation-duration: 10s;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
animation-direction: alternate;
}
@-webkit-keyframes expand {
0% {
-webkit-transform: rotateY(-30deg) rotateX(-40deg);
transform: rotateY(-30deg) rotateX(-40deg);
}
100% {
-webkit-transform: rotateY(20deg) rotateX(-35deg);
transform: rotateY(20deg) rotateX(-35deg);
}
}
@keyframes expand {
0% {
-webkit-transform: rotateY(-30deg) rotateX(-40deg);
transform: rotateY(-30deg) rotateX(-40deg);
}
100% {
-webkit-transform: rotateY(20deg) rotateX(-35deg);
transform: rotateY(20deg) rotateX(-35deg);
}
}
/*
* CUSTOM DROP
* https://codepen.io/Thibaut/pen/Jasci
*/
.dropdown {
display: inline-block;
position: relative;
overflow: hidden;
vertical-align: middle;
height: 28px;
width: 150px;
background: #f2f2f2;
line-height: 20px;
border: 1px solid;
border-color: white #f7f7f7 whitesmoke;
border-radius: 3px;
background-image: -webkit-gradient(linear, left top, left bottom, from(transparent), to(rgba(0, 0, 0, 0.06)));
background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.06));
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.08);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.08);
}
.dropdown:before, .dropdown:after {
content: '';
position: absolute;
z-index: 2;
top: 9px;
right: 10px;
width: 0;
height: 0;
border: 4px dashed;
border-color: #888888 transparent;
pointer-events: none;
}
.dropdown:before {
border-bottom-style: solid;
border-top: none;
}
.dropdown:after {
margin-top: 7px;
border-top-style: solid;
border-bottom: none;
}
.dropdown-select {
position: relative;
width: 130%;
margin: 0;
padding: 6px 8px 6px 10px;
height: 28px;
line-height: 14px;
font-size: 16px;
color: #62717a;
text-shadow: 0 1px white;
background: #f2f2f2;
/* Fallback for IE 8 */
background: rgba(0, 0, 0, 0) !important;
/* "transparent" doesn't work with Opera */
border: 0;
border-radius: 0;
-webkit-appearance: none;
}
.dropdown-select:focus {
z-index: 3;
width: 100%;
color: #394349;
outline: 2px solid #49aff2;
outline: 2px solid -webkit-focus-ring-color;
outline-offset: -2px;
}
.dropdown-select > option {
margin: 3px;
padding: 6px 8px;
text-shadow: none;
background: #f2f2f2;
border-radius: 3px;
cursor: pointer;
}
/* Fix for IE 8 putting the arrows behind the select element. */
.lt-ie9 .dropdown {
z-index: 1;
}
.lt-ie9 .dropdown-select {
z-index: -1;
}
.lt-ie9 .dropdown-select:focus {
z-index: 3;
}
/* Dirty fix for Firefox adding padding where it shouldn't. */
@-moz-document url-prefix() {
.dropdown-select {
padding-left: 6px;
}
}
/*
* CUSTOM CHECKBOX
* https://codepen.io/CreativeJuiz/pen/BiHzp
*/
/* Base for label styling */
[type="checkbox"]:not(:checked),
[type="checkbox"]:checked {
position: absolute;
left: -9999px;
}
[type="checkbox"]:not(:checked) + label,
[type="checkbox"]:checked + label {
position: relative;
padding-left: 25px;
cursor: pointer;
}
/* checkbox aspect */
[type="checkbox"]:not(:checked) + label:before,
[type="checkbox"]:checked + label:before {
content: '';
position: absolute;
left: 0;
top: 2px;
width: 17px;
height: 17px;
border: 1px solid #aaa;
background: #f8f8f8;
border-radius: 3px;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
}
/* checked mark aspect */
[type="checkbox"]:not(:checked) + label:after,
[type="checkbox"]:checked + label:after {
content: '?';
position: absolute;
top: 0;
left: -2px;
font-size: 35px;
color: #47AFC4;
-webkit-transition: all .2s;
transition: all .2s;
}
/* checked mark aspect changes */
[type="checkbox"]:not(:checked) + label:after {
opacity: 0;
-webkit-transform: scale(0);
transform: scale(0);
}
[type="checkbox"]:checked + label:after {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
/* disabled checkbox */
[type="checkbox"]:disabled:not(:checked) + label:before,
[type="checkbox"]:disabled:checked + label:before {
-webkit-box-shadow: none;
box-shadow: none;
border-color: #bbb;
background-color: #ddd;
}
[type="checkbox"]:disabled:checked + label:after {
color: #999;
}
[type="checkbox"]:disabled + label {
color: #aaa;
}
/* accessibility */
[type="checkbox"]:checked:focus + label:before,
[type="checkbox"]:not(:checked):focus + label:before {
border: 1px dotted blue;
}
</style>
</head>
<h1 >
Spiele mit Piano
</h1>
<div id="alles">
<div class="menu1">
<input id="volume" type="range" min="0" max="1" step="0.1" value="0.1"/>+
<label for="instrument">Instruments</label>
<div class="dropdown">
<select id='instrument' class="dropdown-select">
<option value="1">Church Organ</option>
<option value="2">Cloud Song</option>
<option value="3">Tom Crazy</option>
<option value="4">Phone</option>
</select>
</div>
<span> <input type="checkbox" value='vibrato' id="vibrato">
<label for="vibrato">Vibrato</label>
</span>
</div>
<div class="scene">
<div class="piano animate" id="piano">
</div>
</div>
</div>
<script>
;(function( win, doc, $ ){
'use strict';
var __KEYSPRESSED = [],
__PLAYINGNOTES = [],
__STOPPEDNOTES = [],
__INSTRUMENT = 1,
__VOLUME = 0.1,
__VIBRATO = false,
__OCTAVE = 3,
audio_context,
oscillator;
function Piano( octave, target ) {
this.octave = octave;
this.notes = ['c', 'd', 'e', 'f', 'g', 'a', 'b'];
this.susNotes = ['c', 'd', 'f', 'g', 'a'];
this.mapNotes = ['c', 'd', 'e', 'f', 'g', 'a', 'b','c#', 'd#', 'f#', 'g#', 'a#', 'c', 'd', 'e', 'c#', 'd#', 'f#', 'g#'];
this.keymap = ['a', 's', 'd', 'f', 'g','h', 'j','w', 'e', 'r', 't', 'y', 'k', 'l', 'ç', 'u', 'i', 'o', 'p'];
this.target = target;
this.init();
}
Piano.prototype = {
init: function() {
this.$target = $( this.target );
this.createKeys();
this.bindEvents();
this.changeOctave();
},
createKeys: function() {
var key,whiteW=60, blackW = ( whiteW / 2 ), o = this.octave, wWidth=0, bWidth=blackW + (blackW/2);
for( var k=0; k<o; k+=1 ) {
for( var i=0, l=this.notes.length; i<l; i+=1 ) {
key = this.createKey();
key.find( '.f-notes' ).html( this.notes[ i ].toUpperCase() );
key.addClass( 'white-key-group' );
key.addClass( 'key' );
key.addClass( 'tom-' + this.notes[ i ] );
key.attr('data-note', this.notes[ i ].toUpperCase() + ( k + 3 ) );
key.css('left', wWidth + 'px' );
this.$target.append( key );
wWidth += whiteW;
if( i !== 2 && i !== 6 ) {
key = this.createKey();
key.find( '.f-notes' ).html( this.notes[ i ].toUpperCase() + '#' );
key.addClass( 'black-key-group' );
key.addClass( 'key' );
key.addClass( 'tom-s' + this.notes[ i ] );
key.attr('data-note', this.notes[ i ].toUpperCase() + '#' + ( k + 3 ) );
key.css('left', bWidth + 'px' );
this.$target.append( key );
}
bWidth += whiteW;
}
}
},
changeOctave: function( octave ) {
var self = this;
self.$target.find( '.f-keymap' ).html( '' );
var i=0, j=0, oc = octave || __OCTAVE;
this.mapNotes.forEach( function( e ) {
if( i===12 ) {
oc++ ; i=0;
}
self.$target.find( 'div[data-note='+ e.toUpperCase() + oc + ']').find('.f-keymap').html( self.keymap[ j ].toUpperCase() );
i++;
j++;
});
},
createKey: function() {
return $('<div><div class="tec y90-left size-lr"></div><div class="tec y90-right size-lr"></div><div class="tec x90-top keyTop size-t"></div><div class="tec x90-front"><span class="f-keymap"></span><span class="f-notes"></span></div> </div> ');
},
bindEvents: function() {
var $keys = $( '.key' );
$keys.on( 'mouseenter', function( e ) {
var $el = $( e.currentTarget ), freqs, freq;
if( $el.hasClass('white-key-group') ) {
$el.addClass( 'pressed' );
} else {
$el.addClass( 'pressed-black ' );
}
$el.addClass( 'active' );
freq = mplay.getFrequency( $el.attr( 'data-note' ) );
freqs = mplay.getInstrument( freq, __INSTRUMENT, __VIBRATO );
mplay.play( freqs );
});
$keys.on( 'mouseout', function( e ) {
var $el = $( e.currentTarget );
if( $el.hasClass('white-key-group') ) {
$el.removeClass( 'pressed' );
} else {
$el.removeClass( 'pressed-black ' );
}
$el.removeClass( 'active' );
mplay.stop();
});
}
};
$( doc ).ready(function() {
var $oct1 = $( '#oct1' ),$oct2 = $( '#oct2' );
var _changeOctave = function( oct ) {
if( oct ) {
$oct1.addClass( 'b-active' );
$oct2.removeClass( 'b-active' );
} else {
$oct1.removeClass( 'b-active' );
$oct2.addClass( 'b-active' );
}
};
try {
var Tmp = win.AudioContext || win.webkitAudioContext;
audio_context = new Tmp();
} catch (e) {
alert('No web audio oscillator support in this browser');
}
$( doc ).keydown(function( e ) {
e.preventDefault();
if( __KEYSPRESSED.indexOf( e.which ) === -1 ) {
__KEYSPRESSED.push( e.which );
}
if( e.which === 49 ) {
__OCTAVE = 3;
piano.changeOctave();
_changeOctave( true );
}
if( e.which === 50 ) {
__OCTAVE = 4;
piano.changeOctave();
_changeOctave( false );
}
});
$( doc ).keyup(function( e ) {
e.preventDefault();
var io = __KEYSPRESSED.indexOf( e.which );
if( io !== -1 ) {
__KEYSPRESSED.splice( io, 1 );
__STOPPEDNOTES.push( e.which );
}
});
$( '#vibrato').on( 'change', function( e ) {
__VIBRATO = $( e.currentTarget ).is(':checked') ? true : false;
});
$( '#animate').on( 'change', function( e ) {
if( $( e.currentTarget ).is(':checked') ) {
win.piano.$target.addClass( 'animate' );
} else {
win.piano.$target.removeClass( 'animate' );
}
});
$( '#instrument').on( 'change', function( e ) {
__INSTRUMENT = +e.currentTarget.selectedIndex + 1;
});
$( '#volume').on( 'change', function( e ) {
__VOLUME = +e.currentTarget.value;
});
$( '#notes' ).on( 'change', function( e ) {
if( $( e.currentTarget ).is(':checked') ) {
win.piano.$target.find( '.f-notes' ).addClass( 'info-active' );
} else {
win.piano.$target.find( '.f-notes' ).removeClass( 'info-active' );
}
});
$( '#keymap' ).on( 'change', function( e ) {
if( $( e.currentTarget ).is(':checked') ) {
win.piano.$target.find( '.f-keymap' ).addClass( 'info-active' );
} else {
win.piano.$target.find( '.f-keymap' ).removeClass( 'info-active' );
}
});
$( '.box' ).on( 'click', function( e ) {
if( $( e.currentTarget ).attr( 'id' ) === 'oct1' ) {
__OCTAVE = 3;
piano.changeOctave();
_changeOctave( true );
} else {
__OCTAVE = 4;
piano.changeOctave();
_changeOctave( false );
}
});
win.piano = new Piano(3, '#piano');
setInterval( mplay.render, 0 );
});
var mplay = {};
var fq = [];
mplay.play = function ( freqs, key ) {
var oscs = [], o, i, g;
freqs.forEach( function( freq ) {
g = createGain();
g.gain.value = __VOLUME;
o = audio_context.createOscillator();
o.frequency.value = freq;
o.connect( g );
g.connect( audio_context.destination );
_play( 0 );
oscs.push( o );
});
fq[ key ] = oscs;
function createGain() {
var out;
if( audio_context.createGain ) {
out = audio_context.createGain();
} else if ( audio_context.createGainNode ) {
out = audio_context.createGainNode();
}
return out;
}
function _play( arg ) {
if( o.noteOn ) {
o.noteOn( arg );
} else if ( o.start ) {
o.start( arg );
}
}
};
mplay.stop = function ( key ) {
fq[ key ].forEach( function( o ) {
_stop( 0, o );
});
function _stop( arg, o ) {
if( o.noteOff ) {
o.noteOff( arg );
} else if ( o.stop ) {
o.stop( arg );
}
}
};
mplay.getKeyMap = function( map ) {
switch( map ) {
case 65:
return 'C' + __OCTAVE;
case 83:
return 'D' + __OCTAVE;
case 68:
return 'E' + __OCTAVE;
case 70:
return 'F' + __OCTAVE;
case 71:
return 'G' + __OCTAVE;
case 72:
return 'A' + __OCTAVE;
case 74:
return 'B' + __OCTAVE;
case 87:
return 'C#' + __OCTAVE;
case 69:
return 'D#' + __OCTAVE;
case 82:
return 'F#' + __OCTAVE;
case 84:
return 'G#' + __OCTAVE;
case 89:
return 'A#' + __OCTAVE;
case 75:
return 'C' + ( __OCTAVE + 1 );
case 76:
return 'D' + ( __OCTAVE + 1 );
case 186:
return 'E' + ( __OCTAVE + 1 );
case 220:
return 'F' + ( __OCTAVE + 1 );
case 85:
return 'C#' + ( __OCTAVE + 1 );
case 73:
return 'D#' + ( __OCTAVE + 1 );
case 79:
return 'F#' + ( __OCTAVE + 1 );
case 80:
return 'G#' + ( __OCTAVE + 1 );
case 65:
return 'A#' + ( __OCTAVE + 1 );
default:
return false;
}
};
mplay.render = function() {
var freq, keyMap, $el;
__KEYSPRESSED.forEach( function( key ) {
if( __PLAYINGNOTES.indexOf( key ) === -1 ) {
keyMap = mplay.getKeyMap( key );
if( keyMap ) {
freq = mplay.getFrequency( keyMap );
mplay.play( mplay.getInstrument( freq, __INSTRUMENT, __VIBRATO ), key );
__PLAYINGNOTES.push( key );
$el = $('div[data-note=' + keyMap + ']');
if( $el.hasClass('white-key-group') ) {
$el.addClass( 'pressed' );
} else {
$el.addClass( 'pressed-black ' );
}
$el.addClass( 'active' );
}
}
});
__STOPPEDNOTES.forEach( function( key ) {
keyMap = mplay.getKeyMap( key );
if( keyMap ) {
mplay.stop( key );
__STOPPEDNOTES.splice( __STOPPEDNOTES.indexOf( key ), 1 );
__PLAYINGNOTES.splice( __PLAYINGNOTES.indexOf( key ), 1 );
$el = $('div[data-note=' + keyMap + ']');
if( $el.hasClass('white-key-group') ) {
$el.removeClass( 'pressed' );
} else {
$el.removeClass( 'pressed-black ' );
}
$el.removeClass( 'active' );
}
});
};
// From Retrojs
// https://github.com/eshiota/retro-audio-js
mplay.getFrequency= function (note) {
var notes = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"], octave, keyNumber;
if (note.length === 3) {
octave = note.charAt(2);
} else {
octave = note.charAt(1);
}
octave = +octave + 1;
keyNumber = notes.indexOf(note.slice(0, -1));
if (keyNumber < 3) {
keyNumber = keyNumber + 12 + ((octave - 1) * 12) + 1;
} else {
keyNumber = keyNumber + ((octave - 1) * 12) + 1;
}
// Return frequency of note
return Math.floor(440 * Math.pow(2, (keyNumber - 49) / 12));
};
mplay.getInstrument = function( freq, instrument, vibrato ) {
var freqs = [];
switch( instrument ) {
case 1:
freqs.push( freq );
freqs.push( freq * 2 );
freqs.push( freq * 4 );
freqs.push( freq * 8.5);
freqs.push( freq * 19 );
freqs.push( freq / 2 );
break;
case 2:
freqs.push( freq );
freqs.push( freq * (freq / ( freq -1 ) ) );
freqs.push( freq * (freq / ( freq -5 ) ) );
freqs.push( freq * (freq * ( freq -22 ) ) );
freqs.push( freq * 4 );
freqs.push( freq / 2 );
freqs.push( freq / 3 );
break;
case 3:
freqs.push( freq );
freqs.push( freq * (freq * ( freq -122 ) ) );
freqs.push( freq * (freq * ( freq -22 ) ) );
freqs.push( freq * (freq * ( freq -2 ) ) );
freqs.push( freq * 23 );
freqs.push( freq * 1.221 );
freqs.push( freq / 2 );
freqs.push( freq / 2.2 );
freqs.push( freq / 3 );
break;
case 4:
freqs.push( freq * 2 );
freqs.push( freq / 2 );
break;
}
if( vibrato ) {
freqs.push( freq * (freq / ( freq -5 ) ) );
}
return freqs;
};
}( window, document, $ ));
</script>