harunpehlivan
3/4/2018 - 2:01 AM

Piano Please

Piano Please

body {
    margin: 0;
}

html,
body,
.wrapper {
    height: 100%;
}

.wrapper {
    display: flex;
    flex-flow: column nowrap;
    align-items: center;
    justify-content: center;
}

.piano {
    background-color: #ccc;
    padding: 20px;
    height: 300px;
    width: 785px;
    border-radius: 20px;
    transform: scale(1);
}

.key {
    position: relative;
    float: left;
    margin-top: 50px;
    border-radius: 0 0 0.5rem 0.5rem;
}


.key.key--black {
    background-image: linear-gradient(#1a1a1a 100%, #444 0%);
    width: 30px;
    height: 150px;
    left: 15px;
    z-index: 2;
    margin-left: -30px;
    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);
}

.key.key--black:active {
    background-image: linear-gradient(#1a1a1a 0%, #444 100%);
}


.key.key--white {
    background-image: linear-gradient(#f1f1f1 100%, #ddd 0%);
    width: 50px;
    height: 250px;
    border: 1px solid #ccc;
}

.key.key--white:last-child {
    border-right: 0;
}

.key.key--white:active {
    background-image: linear-gradient(#f1f1f1 0%, #ddd 100%);
}


@media screen and (max-width: 900px) {
    .piano {
        transform: scale(0.8);
    }
}

@media screen and (max-width: 840px) {
    .piano {
        transform: scale(0.6);
    }
}
// ===== DATA AND GLOBALS ===== //


const audioCtx = new AudioContext();

const frequencies = {
        'c0': 16.35,
        'cis0': 17.32,
        'd0': 18.35,
        'dis0': 19.45,
        'e0': 20.60,
        'f0': 21.83,
        'fis0': 23.12,
        'g0': 24.50,
        'gis0': 25.96,
        'a0': 27.50,
        'ais0': 29.14,
        'b0': 30.87,
        'c1': 32.70,
        'cis1': 34.65,
        'd1': 36.71,
        'dis1': 38.89,
        'e1': 41.20,
        'f1': 43.65,
        'fis1': 46.25,
        'g1': 49.00,
        'gis1': 51.91,
        'a1': 55.00,
        'ais1': 58.27,
        'b1': 61.74,
        'c2': 65.41,
        'cis2': 69.30,
        'd2': 73.42,
        'dis2': 77.78,
        'e2': 82.41,
        'f2': 87.31,
        'fis2': 92.50,
        'g2': 98.00,
        'gis2': 103.83,
        'a2': 110.00,
        'ais2': 116.54,
        'b2': 123.47,
        'c3': 130.81,
        'cis3': 138.59,
        'd3': 146.83,
        'dis3': 155.56,
        'e3': 164.81,
        'f3': 174.61,
        'fis3': 185.00,
        'g3': 196.00,
        'gis3': 207.65,
        'a3': 220.00,
        'ais3': 233.08,
        'b3': 246.94,
        'c4': 261.63,
        'cis4': 277.18,
        'd4': 293.66,
        'dis4': 311.13,
        'e4': 329.63,
        'f4': 349.23,
        'fis4': 369.99,
        'g4': 392.00,
        'gis4': 415.30,
        'a4': 440.00,
        'ais4': 466.16,
        'b4': 493.88, // continue from here
        'c5': 65.41,
        'cis5': 69.30,
        'd5': 73.42,
        'dis5': 77.78,
        'e5': 82.41,
        'f5': 87.31,
        'fis5': 92.50,
        'g5': 98.00,
        'gis5': 103.83,
        'a5': 110.00,
        'ais5': 116.54,
        'b5': 123.47,
        'c6': 65.41,
        'cis6': 69.30,
        'd6': 73.42,
        'dis6': 77.78,
        'e6': 82.41,
        'f6': 87.31,
        'fis6': 92.50,
        'g6': 98.00,
        'gis6': 103.83,
        'a6': 110.00,
        'ais6': 116.54,
        'b6': 123.47,
        'c7': 65.41,
        'cis7': 69.30,
        'd7': 73.42,
        'dis7': 77.78,
        'e7': 82.41,
        'f7': 87.31,
        'fis7': 92.50,
        'g7': 98.00,
        'gis7': 103.83,
        'a7': 110.00,
        'ais7': 116.54,
        'b7': 123.47,
        'c8': 65.41,
        'cis8': 69.30,
        'd8': 73.42,
        'dis8': 77.78,
        'e8': 82.41,
        'f8': 87.31,
        'fis8': 92.50,
        'g8': 98.00,
        'gis8': 103.83,
        'a8': 110.00,
        'ais8': 116.54,
        'b8': 123.47
};


// ===== ELEMENTS AND EVENTLISTENERS ===== //


const keys = Array.from(document.querySelectorAll('.key'));
keys.forEach(k => k.addEventListener('click', playSound))


// ===== LOGIC ===== //


function playSound({ target }) {
    const playFrequency = 
          frequencies[target.getAttribute('data-tone')];
    
    const oscillator = audioCtx.createOscillator();
    const gain = audioCtx.createGain();
    
    oscillator.type = 'sine';
    oscillator.frequency.value = playFrequency;
    
    oscillator.connect(gain);
    gain.connect(audioCtx.destination);
    
    oscillator.start(0);
    gain.gain.exponentialRampToValueAtTime(
        0.000001, 
        audioCtx.currentTime + 1
    );
}
<div class="wrapper">
    <div class="controls">
        <span>Octaves</span>
        <input type="text" name="octave-left">
        &nbsp;
        and
        &nbsp;
        <input type="text" name="octave-right">
    </div>
    <div class="piano">
        <div class="key key--white" data-tone="c3"></div>
        <div class="key key--black" data-tone="cis3"></div>
        <div class="key key--white" data-tone="d3"></div>
        <div class="key key--black" data-tone="dis3"></div>
        <div class="key key--white" data-tone="e3"></div>
        <div class="key key--white" data-tone="f3"></div>
        <div class="key key--black" data-tone="fis3"></div>
        <div class="key key--white" data-tone="g3"></div>
        <div class="key key--black" data-tone="gis3"></div>
        <div class="key key--white" data-tone="a3"></div>
        <div class="key key--black" data-tone="ais3"></div>
        <div class="key key--white" data-tone="b3"></div>
        <div class="key key--white" data-tone="c4"></div>
        <div class="key key--black" data-tone="cis4"></div>
        <div class="key key--white" data-tone="d4"></div>
        <div class="key key--black" data-tone="dis4"></div>
        <div class="key key--white" data-tone="e4"></div>
        <div class="key key--white" data-tone="f4"></div>
        <div class="key key--black" data-tone="fis4"></div>
        <div class="key key--white" data-tone="g4"></div>
        <div class="key key--black" data-tone="gis4"></div>
        <div class="key key--white" data-tone="a4"></div>
        <div class="key key--black" data-tone="ais4"></div>
        <div class="key key--white" data-tone="b4"></div>
        <div class="key key--white" data-tone="c5"></div>
    </div>
</div>