Plugin Directory

Changeset 3389724


Ignore:
Timestamp:
11/04/2025 02:12:59 PM (5 months ago)
Author:
santechidea
Message:

Version 1.3.2 – updated features and fixed bugs.

Location:
ptpiano/trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • ptpiano/trunk/PT_Piano_Player.php

    r3364815 r3389724  
    8888                                </button>
    8989                          </div>
     90                          <div class="tempo-control">
     91                                <span>Tempo</span>
     92                                <!-- Left Triangle (Decrease) -->
     93                                <button id="tempo-decrease" class="triangle-button triangle-left" title="Decrease Tempo"></button>
     94
     95                                <!-- Tempo Display -->
     96                                <div id="tempo-display" class="tempo-display">0</div>
     97
     98                                <!-- Right Triangle (Increase) -->
     99                                <button id="tempo-increase" class="triangle-button triangle-right" title="Increase Tempo"></button>
     100                        </div>
    90101                      </div>
    91102                    </div>
    92 
    93 
    94103
    95104                    <div class="col col-right">
     
    282291                            </li>
    283292                        <?php endforeach; ?>
    284                         </ul>                               
     293                        </ul>
     294                       
    285295                </div>
    286296               
    287297                <div class="right-column">
     298               
     299                  <div class="left-panel">
     300                  <div class="pedal-wrapper">
     301                    <div class="pedal-top-cover"></div> <!-- Top box cover -->
     302                    <button id="paddleBtn" class="pedal-button" title="Hold Sustain Pedal"></button>                   
     303                  </div>
     304                </div>
     305               
     306                <div class="right-panel">
    288307                    <?php if ($res_chordtxt): ?>
    289308                        <input id="showchord" value="NOTE / CHORD" type="text" readonly class="showscalechord" />
     
    319338                        </div>
    320339                    </div>
    321                    
     340                  </div>
    322341                </div>
    323342            </div>
  • ptpiano/trunk/js/control.js

    r3356455 r3389724  
    1 document.addEventListener('DOMContentLoaded',function(){const volumeSlider=document.getElementById('volumeControl');const volumeRValue=document.getElementById('volumeRValue');function updateVolumeDisplay(value){volumeRValue.textContent=Math.round(parseFloat(value)*100)}
    2 volumeSlider.addEventListener('input',(e)=>{updateVolumeDisplay(e.target.value)});volumeSlider.addEventListener('dblclick',(e)=>{volumeSlider.value=0.5;updateVolumeDisplay(0.5)});updateVolumeDisplay(volumeSlider.value);window.addEventListener("load",function(){document.querySelector(".ptpiano-loader").style.display="none";document.querySelector(".ptpiano-content").style.display="block"})})
     1document.addEventListener('DOMContentLoaded',function(){const volumeSlider=document.getElementById('volumeControl');const volumeRValue=document.getElementById('volumeRValue');const tempoDisplay=document.getElementById('tempo-display');const tempoIncreaseBtn=document.getElementById('tempo-increase');const tempoDecreaseBtn=document.getElementById('tempo-decrease');function updateVolumeDisplay(value){volumeRValue.textContent=Math.round(parseFloat(value)*100)}
     2volumeSlider.addEventListener('input',(e)=>{updateVolumeDisplay(e.target.value)});volumeSlider.addEventListener('dblclick',(e)=>{volumeSlider.value=0.5;updateVolumeDisplay(0.5)});updateVolumeDisplay(volumeSlider.value);window.addEventListener("load",function(){document.querySelector(".ptpiano-loader").style.display="none";document.querySelector(".ptpiano-content").style.display="block"});const defaultTempo=160;tempoDisplay.textContent=defaultTempo;let tempoInterval;function updateTempo(newTempo){tempoDisplay.textContent=newTempo;pianoRecorder.setTempo(newTempo)}
     3function startChangingTempo(changeFn){changeFn();tempoInterval=setInterval(changeFn,100)}
     4function stopChangingTempo(){clearInterval(tempoInterval)}
     5function increaseTempo(){let currentTempo=parseInt(tempoDisplay.textContent);if(currentTempo<300){currentTempo++;updateTempo(currentTempo)}}
     6function decreaseTempo(){let currentTempo=parseInt(tempoDisplay.textContent);if(currentTempo>30){currentTempo--;updateTempo(currentTempo)}}
     7tempoIncreaseBtn.addEventListener('mousedown',()=>startChangingTempo(increaseTempo));tempoIncreaseBtn.addEventListener('mouseup',stopChangingTempo);tempoIncreaseBtn.addEventListener('mouseleave',stopChangingTempo);tempoDecreaseBtn.addEventListener('mousedown',()=>startChangingTempo(decreaseTempo));tempoDecreaseBtn.addEventListener('mouseup',stopChangingTempo);tempoDecreaseBtn.addEventListener('mouseleave',stopChangingTempo);tempoIncreaseBtn.addEventListener('touchstart',()=>startChangingTempo(increaseTempo));tempoIncreaseBtn.addEventListener('touchend',stopChangingTempo);tempoDecreaseBtn.addEventListener('touchstart',()=>startChangingTempo(decreaseTempo));tempoDecreaseBtn.addEventListener('touchend',stopChangingTempo);const paddleplayButton=document.getElementById('paddleBtn');paddleplayButton.addEventListener('click',async()=>{const markedKeys=document.querySelectorAll('.piano-keys .key.mark');console.log(`Selected keys: ${markedKeys.length}`);if(markedKeys.length===0||markedKeys.length>6)return;const playTogether=!0;if(playTogether){markedKeys.forEach(key=>{const note=key.dataset.key||key.dataset.note;if(note)playTune(note);})}else{for(let i=0;i<markedKeys.length-2;i++){const key=markedKeys[i];const note=key.dataset.key||key.dataset.note;if(note){playTune(note);await new Promise(res=>setTimeout(res,200))}}}})})
  • ptpiano/trunk/js/piano.minor.scale.js

    r3364815 r3389724  
    44return scale}
    55const commonMinorProgressions={'A':['Am','F','C','G'],'A#':['A#m','G#','D#','A#'],'B':['Bm','G','D','A'],'C':['Cm','Ab','Eb','Bb'],'C#':['C#m','A','E','B'],'D':['Dm','Bb','F','C'],'D#':['D#m','B','F#','C#'],'E':['Em','C','G','D'],'F':['Fm','Db','Ab','Eb'],'F#':['F#m','D','A','E'],'G':['Gm','Eb','Bb','F'],'G#':['G#m','E','B','F#'],};selectMinorScaleElement.addEventListener('change',(event)=>{const selectedScale=event.target.value;const scaleNotes=getMinorScale(selectedScale);selectMajorElement.selectedIndex=0;selectMinorElement.selectedIndex=0;selectDiminishedElement.selectedIndex=0;selectAugmentedElement.selectedIndex=0;selectMajorScaleElement.selectedIndex=0;pianoKeys.forEach(keyElement=>keyElement.classList.remove('mark'));pianoKeys.forEach(keyElement=>{if(scaleNotes.some(note=>matchNote(keyElement,note))){keyElement.classList.add('mark')}
    6 if(scaleNotes.length){showchord.value=`${selectedScale} MINOR SCALE`}else{showchord.value=''}});const firstKey=document.querySelector('.piano-keys .key');if(firstKey){firstKey.focus();firstKey.scrollIntoView({behavior:'smooth',block:'center'})}
     6if(scaleNotes.length){showchord.value=`${selectedScale} MAJOR SCALE`}else{showchord.value=''}});const firstKey=document.querySelector('.piano-keys .key');if(firstKey){firstKey.focus();firstKey.scrollIntoView({behavior:'smooth',block:'center'})}
    77const progressionEl=document.getElementById('common-progression');if(commonMinorProgressions[selectedScale]){const progression=commonMinorProgressions[selectedScale].join(' → ');progressionEl.textContent=`Common Progression: ${progression}`}else{progressionEl.textContent=''}})})
  • ptpiano/trunk/js/piano.recorder.js

    r3361001 r3389724  
    11class PianoRecorder{constructor(){this.isRecording=!1;this.recordedNotes=[];this.recordingStartTime=null;this.exportTempo=160;this.timeScale=0.5}
     2setTempo(bpm){this.exportTempo=bpm}
    23startRecording(){this.isRecording=!0;this.recordedNotes=[];this.recordingStartTime=performance.now()}
    34stopRecording(){this.isRecording=!1}
    45recordNote(key,note){if(!this.isRecording)return;const currentTime=performance.now();this.recordedNotes.push({key,note,time:currentTime-this.recordingStartTime,})}
    5 playRecording(playTuneFn,onComplete){console.log("play record call");if(!this.recordedNotes.length)return;let startTime=performance.now();this.playingNotes=[];this.recordedNotes.forEach(note=>{const delay=note.time;const timer=setTimeout(()=>{playTuneFn(note.key)},delay);this.playingNotes.push(timer)});const totalTime=this.recordedNotes[this.recordedNotes.length-1].time;this.playbackTimer=setTimeout(()=>{this.playingNotes=[];this.playbackTimer=null;if(onComplete&&typeof onComplete==="function"){onComplete()}},totalTime+200)}
     6playRecording(playTuneFn,onComplete){if(!this.recordedNotes.length)return;const referenceTempo=160;const tempoScale=referenceTempo/this.exportTempo;console.log(this.exportTempo);let startTime=performance.now();this.playingNotes=[];this.recordedNotes.forEach(note=>{const delay=Math.max(note.time*tempoScale,20);const timer=setTimeout(()=>{playTuneFn(note.key)},delay);this.playingNotes.push(timer)});const lastNoteTime=this.recordedNotes[this.recordedNotes.length-1].time;const totalTime=lastNoteTime*tempoScale;this.playbackTimer=setTimeout(()=>{this.playingNotes=[];this.playbackTimer=null;if(onComplete&&typeof onComplete==="function"){onComplete()}},totalTime+200)}
    67stopPlayback(){if(this.playbackTimer){clearTimeout(this.playbackTimer);this.playbackTimer=null}
    78if(this.playingNotes&&this.playingNotes.length){this.playingNotes.forEach(timer=>clearTimeout(timer));this.playingNotes=[]}}
  • ptpiano/trunk/js/piano.sound.js

    r3364815 r3389724  
    55const note=clickedKey?.dataset.note||key;pianoRecorder.recordNote(key,note)}
    66if(!isDrawing)drawEqualizer();}catch(err){console.error("Error playing sound:",err)}};const drawEqualizer=()=>{isDrawing=!0;const renderFrame=()=>{analyser.getByteFrequencyData(dataArray);canvasCtx.clearRect(0,0,equalizerCanvas.width,equalizerCanvas.height);const canvasWidth=equalizerCanvas.width;const canvasHeight=equalizerCanvas.height;const barCount=bufferLength;const barGap=2;const totalGapWidth=(barCount-1)*barGap;const barWidth=(canvasWidth-totalGapWidth)/barCount;let x=0;for(let i=0;i<barCount;i++){const barHeight=dataArray[i]/2;canvasCtx.fillStyle=`rgb(${barHeight + 100}, 50, 200)`;canvasCtx.fillRect(x,canvasHeight-barHeight,barWidth,barHeight);x+=barWidth+barGap}
    7 requestAnimationFrame(renderFrame)};renderFrame()};pianoKeys.forEach(key=>{allKeys.push(key.dataset.key);key.addEventListener("click",()=>{playTune(key.dataset.key);key.classList.add("glow");setTimeout(()=>{key.classList.remove("glow")},500)})});volumeSlider.addEventListener("input",()=>{});notesCheckbox.addEventListener("click",()=>{pianoKeys.forEach(key=>{const noteLabel=key.querySelector(".note-label");if(noteLabel)noteLabel.classList.toggle("hide");})});keysCheckbox.addEventListener("click",()=>{pianoKeys.forEach(key=>{const keyLabel=key.querySelector(".key-label");if(keyLabel)keyLabel.classList.toggle("hide");})});document.addEventListener("keydown",e=>{const pressedKey=e.key.toLowerCase();if(allKeys.includes(pressedKey)){playTune(pressedKey);const keyElement=document.querySelector(`.key[data-key="${pressedKey}"]`);if(keyElement){keyElement.classList.add("glow");setTimeout(()=>{keyElement.classList.remove("glow")},500)}}});recordBtn.addEventListener("click",()=>{if(!pianoRecorder.isRecording){noteDisplay.innerHTML="";pianoRecorder.startRecording();recordBtn.classList.add('active');playBtn.disabled=!0;clearBtn.disabled=!0;const maxDuration=(typeof ptPianSettings!=='undefined'&&ptPianSettings.recordDuration)?parseInt(ptPianSettings.recordDuration,10)*1000:30000;setTimeout(()=>{if(pianoRecorder.isRecording){pianoRecorder.stopRecording();recordBtn.classList.remove('active');playBtn.disabled=!1;clearBtn.disabled=!1;popup.style.display='flex'}},maxDuration);if(closeBtn){closeBtn.addEventListener("click",()=>{popup.style.display="none";if(pianoRecorder.recordedNotes.length>0){isPlaying=!0;playBtn.classList.add('active');recordBtn.disabled=!0;clearBtn.disabled=!0;noteDisplay.innerHTML="";pianoRecorder.playRecording(playTune,()=>{isPlaying=!1;playBtn.classList.remove('active');recordBtn.disabled=!1;clearBtn.disabled=!1})}})}}else{pianoRecorder.stopRecording();recordBtn.classList.remove('active');playBtn.disabled=!1;clearBtn.disabled=!1}});let isPlaying=!1;noteDisplay.innerHTML="";playBtn.addEventListener("click",()=>{if(!isPlaying){if(pianoRecorder.recordedNotes.length>0){isPlaying=!0;playBtn.classList.add('active');recordBtn.disabled=!0;clearBtn.disabled=!0;noteDisplay.innerHTML="";pianoRecorder.playRecording(playTune,()=>{isPlaying=!1;playBtn.classList.remove('active');recordBtn.disabled=!1;clearBtn.disabled=!1})}else{noteDisplay.innerHTML="Record to play";playBtn.classList.remove('active');playBtn.disabled=!0}}else{if(isPlaying){isPlaying=!1;playBtn.classList.remove('active');recordBtn.disabled=!1;clearBtn.disabled=!1;pianoRecorder.stopPlayback()}}});clearBtn.addEventListener("click",()=>{if(!isPlaying||!pianoRecorder.isRecording){noteDisplay.innerHTML="";for(const key in audioSources){try{audioSources[key].disconnect();delete audioSources[key]}catch(e){console.warn(`Error disconnecting source for key ${key}:`,e)}}}});document.getElementById("mididownloadBtn").addEventListener("click",()=>{pianoRecorder.downloadMidi()});window.playTune=playTune})
     7requestAnimationFrame(renderFrame)};renderFrame()};pianoKeys.forEach(key=>{allKeys.push(key.dataset.key);key.addEventListener("click",()=>{playTune(key.dataset.key);key.classList.add("glow");setTimeout(()=>{key.classList.remove("glow")},500)})});volumeSlider.addEventListener("input",()=>{});notesCheckbox.addEventListener("click",()=>{pianoKeys.forEach(key=>{const noteLabel=key.querySelector(".note-label");if(noteLabel)noteLabel.classList.toggle("hide");})});keysCheckbox.addEventListener("click",()=>{pianoKeys.forEach(key=>{const keyLabel=key.querySelector(".key-label");if(keyLabel)keyLabel.classList.toggle("hide");})});document.addEventListener("keydown",e=>{const pressedKey=e.key.toLowerCase();if(allKeys.includes(pressedKey)){playTune(pressedKey);const keyElement=document.querySelector(`.key[data-key="${pressedKey}"]`);if(keyElement){keyElement.classList.add("glow");setTimeout(()=>{keyElement.classList.remove("glow")},500)}}});recordBtn.addEventListener("click",()=>{if(!pianoRecorder.isRecording){noteDisplay.innerHTML="";pianoRecorder.startRecording();recordBtn.classList.add('active');playBtn.disabled=!0;clearBtn.disabled=!0;const currentTempo=parseInt(document.getElementById('tempo-display').textContent);pianoRecorder.setTempo(currentTempo);const maxDuration=(typeof ptPianSettings!=='undefined'&&ptPianSettings.recordDuration)?parseInt(ptPianSettings.recordDuration,10)*1000:30000;setTimeout(()=>{if(pianoRecorder.isRecording){pianoRecorder.stopRecording();recordBtn.classList.remove('active');playBtn.disabled=!1;clearBtn.disabled=!1;popup.style.display='flex'}},maxDuration);if(closeBtn){closeBtn.addEventListener("click",()=>{popup.style.display="none";if(pianoRecorder.recordedNotes.length>0){isPlaying=!0;playBtn.classList.add('active');recordBtn.disabled=!0;clearBtn.disabled=!0;noteDisplay.innerHTML="";pianoRecorder.playRecording(playTune,()=>{isPlaying=!1;playBtn.classList.remove('active');recordBtn.disabled=!1;clearBtn.disabled=!1})}})}}else{pianoRecorder.stopRecording();recordBtn.classList.remove('active');playBtn.disabled=!1;clearBtn.disabled=!1}});let isPlaying=!1;noteDisplay.innerHTML="";playBtn.addEventListener("click",()=>{if(!isPlaying){if(pianoRecorder.recordedNotes.length>0){const currentTempo=parseInt(document.getElementById('tempo-display').textContent);pianoRecorder.setTempo(currentTempo);isPlaying=!0;playBtn.classList.add('active');recordBtn.disabled=!0;clearBtn.disabled=!0;noteDisplay.innerHTML="";pianoRecorder.playRecording(playTune,()=>{isPlaying=!1;playBtn.classList.remove('active');recordBtn.disabled=!1;clearBtn.disabled=!1})}else{noteDisplay.innerHTML="Record to play";playBtn.classList.remove('active');playBtn.disabled=!0}}else{if(isPlaying){isPlaying=!1;playBtn.classList.remove('active');recordBtn.disabled=!1;clearBtn.disabled=!1;pianoRecorder.stopPlayback()}}});clearBtn.addEventListener("click",()=>{if(!isPlaying||!pianoRecorder.isRecording){noteDisplay.innerHTML="";for(const key in audioSources){try{audioSources[key].disconnect();delete audioSources[key]}catch(e){console.warn(`Error disconnecting source for key ${key}:`,e)}}}});document.getElementById("mididownloadBtn").addEventListener("click",()=>{pianoRecorder.downloadMidi()});window.playTune=playTune})
  • ptpiano/trunk/ptpiano.php

    r3364823 r3389724  
    33 * Plugin Name: PTPiano
    44 * Description: An interactive, browser-based piano plugin for learning and exploring chords and notes.
    5  * Version: 1.3.1
     5 * Version: 1.3.2
    66 * Author: santechidea
    77 * Author URI:  https://wordpress.santechidea.net
  • ptpiano/trunk/readme.txt

    r3364823 r3389724  
    55Tested up to: 6.8
    66Requires PHP: 8.0
    7 Stable tag: 1.3.1
     7Stable tag: 1.3.2
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    5050
    5151== Changelog ==
     52
     53= 1.3.2 =
     54
     55* Bug Fixed
     56
     57* Introduced Tempo setting to allow users to control their recording tempo.
     58
     59* Added a button to play multiple piano button simultaneously for major, minor, diminished, and augmented chords.
     60
     61* Enhance the user interface of plugin piano.
    5262
    5363= 1.3.1 =
  • ptpiano/trunk/styles/piano.css

    r3364815 r3389724  
    1 *{margin:0;padding:0;box-sizing:border-box;font-family:sans-serif}.content-wrapper{padding:5px 10px 15px 10px;border-radius:20px}.content-wrapper header{display:flex;color:#B2B2B2;align-items:center;justify-content:space-between;padding:15px}.columnbox{display:grid;grid-template-columns:1fr 4fr 1fr;align-items:center;padding:15px 20px;background-color:#252424;border-radius:20px;width:100%}.col-left{display:flex;flex-direction:column}.piano-header{display:flex;align-items:center;gap:10px}.piano-title h2{margin:0;font-size:21px;font-weight:700;color:#555;font-style:italic;font-family:fantasy}.piano-title .version{font-size:18px;color:#555;margin-left:6px;font-family:cursive}.piano-speaker img{margin-top:5px;max-width:150px}.col-center{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:15px}.equalizer-notes-row{display:flex;flex-direction:row;gap:5px;align-items:center;justify-content:center;width:100%;max-width:100%}.note-display-wrapper{background:#1e1e1e;border-radius:12px;padding:10px 15px;min-height:100px;box-shadow:inset 0 0 6px rgb(0 0 0 / .6);border:1px solid #444;display:flex;align-items:center;justify-content:flex-start;flex-grow:1;width:90%;min-height:125px;max-width:100%;overflow-x:hidden}.equalizer-wrapper{background:#1e1e1e;border-radius:12px;padding:10px 15px;box-shadow:inset 0 0 6px rgb(0 0 0 / .6);border:1px solid #444;display:flex;align-items:center;justify-content:center;width:220px;min-height:100px}.note-display{width:100%;height:100px;overflow-x:hidden;overflow-y:auto;white-space:normal;padding:8px 12px;background:#121212;border-radius:8px;color:#eee;font-family:monospace,monospace;font-size:16px;user-select:text;box-sizing:border-box}#played-notes{display:flex;flex-wrap:wrap;align-items:flex-start;overflow-x:hidden;overflow-y:auto;background:#121212;border-radius:8px;padding:8px 12px;height:100px;color:#eee;font-family:monospace;font-size:16px;box-sizing:border-box;gap:6px 8px;line-height:1}#played-notes::-webkit-scrollbar{width:10px}#played-notes::-webkit-scrollbar-track{background:#1e1e1e;border-radius:10px}#played-notes::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#ff6ec4,#7873f5);border-radius:10px;border:2px solid #1e1e1e}#played-notes::-webkit-scrollbar-thumb:hover{background:linear-gradient(135deg,#ff8ec4,#9893f5)}.played-note{display:inline-block;padding:2px 6px;background-color:#2a2a2a;border-radius:4px;white-space:nowrap;margin:0;line-height:1}#equalizer{width:220px}.col-right{display:flex;flex-direction:column;padding:5px 0 0 15px}#enable-piano-btn{padding:10px 20px;font-size:16px;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color 0.3s ease,box-shadow 0.3s ease}#enable-piano-btn.enabled{background-color:green;color:#fff;box-shadow:0 0 10px 2px rgb(0 255 0 / .8)}#enable-piano-btn.disabled{background-color:red;color:#fff;box-shadow:none}.vol-notes-row{display:flex;flex-wrap:wrap;align-items:center;gap:15px;margin-top:10px;justify-content:center}.volume-slider{display:flex;align-items:center;background:#555;padding:10px 15px;border-radius:40px;width:320px;gap:12px;font-family:sans-serif;color:#00fdfd}.volume-icon{font-size:20px}#volumeControl{-webkit-appearance:none;appearance:none;width:100%;height:8px;background:linear-gradient(to bottom,#555,#1E1E1E);border-radius:3px;cursor:pointer}#volumeControl::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:21px;height:30px;background:linear-gradient(to right,#555,#ccc),linear-gradient(to bottom,#444,#111);background-repeat:no-repeat;background-position:center;background-size:100% 6px,cover;border:2px solid #888;border-radius:3px;box-shadow:0 2px 6px rgb(0 0 0 / .4);margin-top:2px;z-index:3;position:relative}#volumeControl::-moz-range-thumb{width:21px;height:30px;background:linear-gradient(to right,#ccc,#ccc),linear-gradient(to bottom,#444,#111);background-repeat:no-repeat;background-position:center;background-size:100% 2px,cover;border:2px solid #888;border-radius:3px;box-shadow:0 2px 6px rgb(0 0 0 / .4)}#volumeRValue{font-weight:700;min-width:32px;text-align:right;color:orange}.button-box{display:flex;flex-wrap:wrap;gap:10px;background:#555;padding:10px 20px;border-radius:40px;font-family:sans-serif;justify-content:center}.dotted-btn{position:relative;width:100px;padding:10px 16px;height:auto;background-color:#2b2b2b;border:none;border-radius:8px;box-shadow:inset -4px 4px 8px #1a1a1a,inset 4px -4px 8px #3a3a3a;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform 0.2s}.dotted-btn:hover{transform:scale(.95);box-shadow:inset 3px 3px 6px rgb(0 0 0 / .6),inset -3px -3px 6px rgb(255 255 255 / .05);transition:transform 0.2s,box-shadow 0.2s}.dotted-btn::before{content:"";position:absolute;width:80%;height:80%;background-image:radial-gradient(#000 2px,transparent 0);background-size:8px 8px;top:50%;left:50%;transform:translate(-50%,-50%);opacity:.3;pointer-events:none;border-radius:6px}.button-content{display:flex;align-items:center;gap:8px;z-index:1;background-color:#252525}.indicator{width:12px;height:12px;background-color:#ff2e2e;border-radius:50%;transition:box-shadow 0.3s ease,opacity 0.3s ease;opacity:.5}.indicatorp{width:12px;height:12px;background-color:#00FDFD;border-radius:50%;transition:box-shadow 0.3s ease,opacity 0.3s ease;opacity:.5}.dotted-btn.active .indicator{box-shadow:0 0 12px 4px #ff2e2e;opacity:1}.dotted-btn.active .indicatorp{box-shadow:0 0 12px 4px #00FDFD;opacity:1}.btn-label{font-size:18px;color:#555;background-color:#fff0}#clearBtn{transition:background-color 0.2s ease,color 0.2s ease,opacity 0.2s ease}.chord-group{display:inline-block;text-align:center;position:relative;margin:0 20px}.chord-label{position:absolute;top:-18px;left:50%;transform:translateX(-50%);color:#252424;font-size:18px;font-weight:700;background:#070707;z-index:2;padding:5px 10px 0 10px;border-radius:10px 10px 0 0}.chord-option{display:inline-flex;gap:10px;padding:15px;border-radius:0 0 10px 10px;background:#070707;position:relative}.chord-option::before{content:"";position:absolute;top:-2px;left:0;width:100%;height:2px;background:#252424}.chord-option select{background-color:#252424;border:2px solid #555;border-radius:8px;padding:10px 16px;font-weight:700;font-family:Arial,Helvetica,sans-serif;font-size:14px;outline:none;transition:background-color 0.3s,color 0.3s;width:155px}select option{background-color:#252424;font-weight:400}.columnboxpiano{display:flex;flex-direction:row;flex-wrap:wrap;align-items:flex-start;padding:15px 0 0 0;background-color:#252424;border-radius:20px;width:100%;box-sizing:border-box;gap:10px}.left-column{width:72%}.left-column,.right-column{display:flex;flex-direction:column;gap:10px;color:#fff;box-sizing:border-box}.content-wrapper .control{display:flex;color:#252424;align-items:center;justify-content:space-between;padding:15px}.control .column{display:flex;align-items:center;gap:5px}.control span{font-weight:500;margin-right:15px;font-size:1.19rem}.control input{outline:none;border-radius:30px}.piano-keys{display:flex;list-style:none;margin-top:40px;padding:20px}ul.piano-keys{list-style-type:none!important}.piano-keys .key{cursor:pointer;user-select:none;position:relative;text-transform:uppercase}.piano-keys .white,.piano-keys .black{transition:transform 0.08s ease-in,box-shadow 0.1s ease,background 0.1s ease;will-change:transform}.piano-keys .black{z-index:3;width:44px;height:140px;margin:0 -22px 0 -22px;border-radius:0 0 5px 5px;background:linear-gradient(#333,#000);box-shadow:0 4px 8px rgb(0 0 0 / .6),inset 0 -2px 2px rgb(255 255 255 / .05);transition:transform 0.08s ease-in,box-shadow 0.1s ease,background 0.1s ease}.piano-keys .black.active{transform:scale(.96) translateY(1px);background:linear-gradient(to bottom,#000,#434343);box-shadow:inset -5px -10px 10px rgb(255 255 255 / .1),0 2px 10px rgb(0 0 0 / .5)}.piano-keys .white{height:230px;width:70px;border-radius:8px;border:1px solid #000;background:linear-gradient(#fff 96%,#eee 4%)}.piano-keys .white.active{transform:scale(.97);box-shadow:inset -5px 5px 20px rgb(0 0 0 / .2),0 2px 6px rgb(0 0 0 / .3);background:linear-gradient(to bottom,#fff 0%,#eee 100%)}.piano-keys .key span{position:absolute;bottom:20px;width:80%;font-size:1.13rem;text-align:center}.piano-keys .black span{bottom:21px;color:#888}.hide{display:none!important}.piano-keys .key span.note-label{display:block;bottom:29px}.piano-keys .key span.key-label{display:block;font-size:12px;color:#555;bottom:9px}.right-column{width:26%}.ctl-label{color:#555}.showscalechord{appearance:none;border:none;outline:none;background:#252424;border-radius:.2em .2em 0 0;text-align:center;padding:.6em;margin:0 auto;color:#fff}.toggle-box{background:#252424;padding:10px 15px 20px 15px;border-radius:40px;font-family:sans-serif;margin:0 auto}.keys-checkbox{display:flex;align-items:center;gap:10px;margin:10px 0;font-family:sans-serif;width:100%}.keys-checkbox input{height:30px;width:60px;cursor:pointer;appearance:none;position:relative;background:#4B4B4B}.keys-checkbox input::before{content:"";position:absolute;top:50%;left:5px;width:20px;height:20px;border-radius:50%;background:#8c8c8c;transform:translateY(-50%);transition:all 0.3s ease}.keys-checkbox input:checked::before{left:35px;background:#fff}.switch input{opacity:0;width:0;height:0}.switch{position:relative;display:inline-block;width:65px;height:26px}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;transition:0.4s;border-radius:26px;width:50px}.slider::before{content:"";position:absolute;height:20px;width:20px;left:3px;bottom:3px;background:linear-gradient(to bottom right,#555,#ccc);transition:0.4s;border-radius:50%}.switch input:checked+.slider{width:50px}.switch input:checked+.slider::before{transform:translateX(24px)}.reverb-box{background:#252424;padding:10px 15px 20px 15px;border-radius:40px;font-family:sans-serif;margin:0 auto}.reverb-box select{background-color:#252424;color:gold;border:2px solid #555;border-radius:8px;padding:10px 16px;font-weight:700;font-family:Arial,Helvetica,sans-serif;font-size:14px;outline:none;transition:background-color 0.3s,color 0.3s;width:95px}.ptpiano-wrapper{position:relative;min-height:300px;background:#fff0}.ptpiano-loader{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:10}.ptpiano-loader p{margin-top:15px;font-size:14px;font-weight:700;color:#333}.spinner{width:40px;height:40px;border:4px solid #ddd;border-top:4px solid cyan;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{100%{transform:rotate(360deg)}}.popup-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgb(0 0 0 / .75);display:none;justify-content:center;align-items:center;z-index:9999;pointer-events:all}.popup-content{background:#252424;padding:25px 30px;color:#fff;border-radius:12px;text-align:center;max-width:350px;box-shadow:0 10px 25px rgb(0 0 0 / .3);animation:fadeInScale 0.3s ease-in-out;font-family:'Segoe UI',sans-serif}.popup-content h3{margin-top:0;color:#555}.popup-content p{color:#555;margin:15px 0}.popup-content button{background-color:#3a7afe;color:#fff;border:none;padding:10px 18px;font-size:14px;border-radius:6px;cursor:pointer}.popup-content button:hover{background-color:#245fd3}@media screen and (max-width:1280px){.content-wrapper{padding:5px}header{flex-direction:column}header :where(h2,.column){margin-bottom:13px}.piano-header{width:170px!important}.piano-speaker{display:none}.col-center{grid-column:1 / -1;width:100%;padding-left:0;align-items:center}#played-notes{width:120px!important}.content-wrapper .control{display:block!important}.chord-group{display:block!important;margin:0!important}.chord-option select{display:block;width:100%!important;margin-left:0}.chord-option::before{display:none}.chord-label{display:none}.left-column{width:99%!important}.columnboxpiano{flex-direction:column;align-items:center}.piano-keys .black{height:100px;width:44px;margin:0 -20px 0 -20px}.piano-keys .white{height:180px;width:70px}.piano-keys{display:flex;justify-content:space-between;flex-wrap:nowrap;margin:0!important;padding:0 5px}.piano-keys .white{width:9.5vw;height:140px}.piano-keys .black{width:5vw;height:100px;margin:0 -2.5vw}.right-column{width:98%!important;padding:10px 0}canvas#equalizer{width:95%!important;height:auto!important}.piano-keys .key span{font-size:10px}}
     1*{margin:0;padding:0;box-sizing:border-box;font-family:sans-serif}.content-wrapper{padding:5px 10px 15px 10px;border-radius:20px}.content-wrapper header{display:flex;color:#B2B2B2;align-items:center;justify-content:space-between;padding:15px}.columnbox{display:grid;grid-template-columns:1fr 4fr 1fr;align-items:center;padding:15px 20px;background-color:#252424;border-radius:20px;width:100%}.col-left{display:flex;flex-direction:column}.piano-header{display:flex;align-items:center;gap:10px}.piano-title h2{margin:0;font-size:21px;font-weight:700;color:#555;font-style:italic;font-family:fantasy}.piano-title .version{font-size:18px;color:#555;margin-left:6px;font-family:cursive}.piano-speaker img{margin-top:5px;max-width:150px}.col-center{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:15px}.equalizer-notes-row{display:flex;flex-direction:row;gap:5px;align-items:center;justify-content:center;width:100%;max-width:100%}.note-display-wrapper{background:#1e1e1e;border-radius:12px;padding:10px 15px;min-height:100px;box-shadow:inset 0 0 6px rgb(0 0 0 / .6);border:1px solid #444;display:flex;align-items:center;justify-content:flex-start;flex-grow:1;width:90%;min-height:125px;max-width:100%;overflow-x:hidden}.equalizer-wrapper{background:#1e1e1e;border-radius:12px;padding:10px 15px;box-shadow:inset 0 0 6px rgb(0 0 0 / .6);border:1px solid #444;display:flex;align-items:center;justify-content:center;width:220px;min-height:100px}.note-display{width:100%;height:100px;overflow-x:hidden;overflow-y:auto;white-space:normal;padding:8px 12px;background:#121212;border-radius:8px;color:#eee;font-family:monospace,monospace;font-size:16px;user-select:text;box-sizing:border-box}#played-notes{display:flex;flex-wrap:wrap;align-items:flex-start;overflow-x:hidden;overflow-y:auto;background:#121212;border-radius:8px;padding:8px 12px;height:100px;color:#eee;font-family:monospace;font-size:16px;box-sizing:border-box;gap:6px 8px;line-height:1}#played-notes::-webkit-scrollbar{width:10px}#played-notes::-webkit-scrollbar-track{background:#1e1e1e;border-radius:10px}#played-notes::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#ff6ec4,#7873f5);border-radius:10px;border:2px solid #1e1e1e}#played-notes::-webkit-scrollbar-thumb:hover{background:linear-gradient(135deg,#ff8ec4,#9893f5)}.played-note{display:inline-block;padding:2px 6px;background-color:#2a2a2a;border-radius:4px;white-space:nowrap;margin:0;line-height:1}#equalizer{width:220px}.col-right{display:flex;flex-direction:column;padding:5px 0 0 15px}#enable-piano-btn{padding:10px 20px;font-size:16px;color:#fff;border:none;border-radius:4px;cursor:pointer;transition:background-color 0.3s ease,box-shadow 0.3s ease}#enable-piano-btn.enabled{background-color:green;color:#fff;box-shadow:0 0 10px 2px rgb(0 255 0 / .8)}#enable-piano-btn.disabled{background-color:red;color:#fff;box-shadow:none}.vol-notes-row{display:flex;flex-wrap:wrap;align-items:center;gap:15px;margin-top:10px;justify-content:center}.volume-slider{display:flex;align-items:center;background:#555;padding:10px 15px;border-radius:40px;width:250px;gap:12px;font-family:sans-serif;color:#00fdfd}.volume-icon{font-size:20px}#volumeControl{-webkit-appearance:none;appearance:none;width:100%;height:8px;background:linear-gradient(to bottom,#555,#1E1E1E);border-radius:3px;cursor:pointer}#volumeControl::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:21px;height:30px;background:linear-gradient(to right,#555,#ccc),linear-gradient(to bottom,#444,#111);background-repeat:no-repeat;background-position:center;background-size:100% 6px,cover;border:2px solid #888;border-radius:3px;box-shadow:0 2px 6px rgb(0 0 0 / .4);margin-top:2px;z-index:3;position:relative}#volumeControl::-moz-range-thumb{width:21px;height:30px;background:linear-gradient(to right,#ccc,#ccc),linear-gradient(to bottom,#444,#111);background-repeat:no-repeat;background-position:center;background-size:100% 2px,cover;border:2px solid #888;border-radius:3px;box-shadow:0 2px 6px rgb(0 0 0 / .4)}#volumeRValue{font-weight:700;min-width:32px;text-align:right;color:orange}.button-box{display:flex;flex-wrap:wrap;gap:10px;background:#555;padding:10px 20px;border-radius:40px;font-family:sans-serif;justify-content:center}.dotted-btn{position:relative;width:100px;padding:10px 16px;height:auto;background-color:#2b2b2b;border:none;border-radius:8px;box-shadow:inset -4px 4px 8px #1a1a1a,inset 4px -4px 8px #3a3a3a;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform 0.2s}.dotted-btn:hover{transform:scale(.95);box-shadow:inset 3px 3px 6px rgb(0 0 0 / .6),inset -3px -3px 6px rgb(255 255 255 / .05);transition:transform 0.2s,box-shadow 0.2s}.dotted-btn::before{content:"";position:absolute;width:80%;height:80%;background-image:radial-gradient(#000 2px,transparent 0);background-size:8px 8px;top:50%;left:50%;transform:translate(-50%,-50%);opacity:.3;pointer-events:none;border-radius:6px}.button-content{display:flex;align-items:center;gap:8px;z-index:1;background-color:#252525}.indicator{width:12px;height:12px;background-color:#ff2e2e;border-radius:50%;transition:box-shadow 0.3s ease,opacity 0.3s ease;opacity:.5}.indicatorp{width:12px;height:12px;background-color:#00FDFD;border-radius:50%;transition:box-shadow 0.3s ease,opacity 0.3s ease;opacity:.5}.dotted-btn.active .indicator{box-shadow:0 0 12px 4px #ff2e2e;opacity:1}.dotted-btn.active .indicatorp{box-shadow:0 0 12px 4px #00FDFD;opacity:1}.btn-label{font-size:18px;color:#555;background-color:#fff0}#clearBtn{transition:background-color 0.2s ease,color 0.2s ease,opacity 0.2s ease}.tempo-control{display:flex;align-items:center;justify-content:center;gap:0;user-select:none;font-family:sans-serif}.tempo-display{width:80px;height:50px;background:linear-gradient(to right,#444,#222);color:#fff;font-size:22px;font-weight:700;display:flex;align-items:center;justify-content:center;border-top:2px solid #555;border-bottom:2px solid #555}.triangle-button{width:0;height:0;border-style:solid;background:none;padding:0;margin:0;cursor:pointer;outline:none;border-top:25px solid #fff0;border-bottom:25px solid #fff0;transition:opacity 0.2s ease}.triangle-left{border-right:30px solid #666}.triangle-left:hover{border-right-color:#999}.triangle-right{border-left:30px solid #666}.triangle-right:hover{border-left-color:#999}.chord-group{display:inline-block;text-align:center;position:relative;margin:0 20px}.chord-label{position:absolute;top:-18px;left:50%;transform:translateX(-50%);color:#252424;font-size:18px;font-weight:700;background:#070707;z-index:2;padding:5px 10px 0 10px;border-radius:10px 10px 0 0}.chord-option{display:inline-flex;gap:10px;padding:15px;border-radius:0 0 10px 10px;background:#070707;position:relative}.chord-option::before{content:"";position:absolute;top:-2px;left:0;width:100%;height:2px;background:#252424}.chord-option select{background-color:#252424;border:2px solid #555;border-radius:8px;padding:10px 16px;font-weight:700;font-family:Arial,Helvetica,sans-serif;font-size:14px;outline:none;transition:background-color 0.3s,color 0.3s;width:155px}select option{background-color:#252424;font-weight:400}.columnboxpiano{display:flex;flex-direction:row;flex-wrap:wrap;align-items:flex-start;padding:15px 0 0 0;background-color:#252424;border-radius:20px;width:100%;box-sizing:border-box;gap:10px}.left-column{width:70%}.left-column{display:flex;flex-direction: column;gap:10px;color:#fff;box-sizing:border-box}.right-column{display:flex;gap:10px;color:#fff;box-sizing:border-box}.content-wrapper .control{display:flex;color:#252424;align-items:center;justify-content:space-between;padding:15px}.control .column{display:flex;align-items:center;gap:5px}.control span{font-weight:500;margin-right:15px;font-size:1.19rem}.control input{outline:none;border-radius:30px}.piano-keys{display:flex;list-style:none;margin-top:40px;padding:20px}ul.piano-keys{list-style-type:none!important}.piano-keys .key{cursor:pointer;user-select:none;position:relative;text-transform:uppercase}.piano-keys .white,.piano-keys .black{transition:transform 0.08s ease-in,box-shadow 0.1s ease,background 0.1s ease;will-change:transform}.piano-keys .black{z-index:3;width:44px;height:140px;margin:0 -22px 0 -22px;border-radius:0 0 5px 5px;background:linear-gradient(#333,#000);box-shadow:0 4px 8px rgb(0 0 0 / .6),inset 0 -2px 2px rgb(255 255 255 / .05);transition:transform 0.08s ease-in,box-shadow 0.1s ease,background 0.1s ease}.piano-keys .black.active{transform:scale(.96) translateY(1px);background:linear-gradient(to bottom,#000,#434343);box-shadow:inset -5px -10px 10px rgb(255 255 255 / .1),0 2px 10px rgb(0 0 0 / .5)}.piano-keys .white{height:230px;width:70px;border-radius:8px;border:1px solid #000;background:linear-gradient(#fff 96%,#eee 4%)}.piano-keys .white.active{transform:scale(.97);box-shadow:inset -5px 5px 20px rgb(0 0 0 / .2),0 2px 6px rgb(0 0 0 / .3);background:linear-gradient(to bottom,#fff 0%,#eee 100%)}.piano-keys .key span{position:absolute;bottom:20px;width:80%;font-size:1.13rem;text-align:center}.piano-keys .black span{bottom:21px;color:#888}.hide{display:none!important}.piano-keys .key span.note-label{display:block;bottom:29px}.piano-keys .key span.key-label{display:block;font-size:12px;color:#555;bottom:9px}.right-column{width:26%}.ctl-label{color:#555}.showscalechord{width:95%;appearance:none;border:none;outline:none;background:#252424;border-radius:.8em;text-align:center;padding:.6em;margin-bottom:5px;color:#fff}.left-panel{width:10%;display:flex;justify-content:center;align-items:flex-end;padding:10px}.right-panel{width:90%}.pedal-wrapper{display:flex;flex-direction:column;align-items:center;margin-top:0;position:relative}.pedal-top-cover{width:40px;height:25px;background:#252424;border-top-left-radius:6px;border-top-right-radius:6px;border-bottom-left-radius:0;border-bottom-right-radius:0;box-shadow:0 4px 8px rgb(0 0 0 / .4);border:5px solid #252424;margin-bottom:-5px;position:relative}.pedal-button{width:40px;height:110px;background:repeating-linear-gradient(45deg,#333,#333 4px,#555 4px,#555 8px);border-radius:10% 10% 70% 70% / 50% 50% 30% 30%;border:2px solid #777;box-shadow:inset -2px -2px 5px rgb(255 255 255 / .6),inset 2px 2px 5px rgb(0 0 0 / .2),0 6px 12px rgb(0 0 0 / .4);cursor:pointer;transition:transform 0.1s ease,box-shadow 0.1s ease;outline:none;position:relative;z-index:1}.pedal-button:active{transform:translateY(3px);box-shadow:inset 1px 1px 3px rgb(0 0 0 / .4),0 4px 6px rgb(0 0 0 / .2)}.toggle-box{background:#252424;padding:10px 15px 20px 15px;border-radius:40px;font-family:sans-serif;margin-bottom:10px}.keys-checkbox{display:flex;align-items:center;gap:10px;margin:10px 0;font-family:sans-serif;width:100%}.keys-checkbox input{height:30px;width:60px;cursor:pointer;appearance:none;position:relative;background:#4B4B4B}.keys-checkbox input::before{content:"";position:absolute;top:50%;left:5px;width:20px;height:20px;border-radius:50%;background:#8c8c8c;transform:translateY(-50%);transition:all 0.3s ease}.keys-checkbox input:checked::before{left:35px;background:#fff}.switch input{opacity:0;width:0;height:0}.switch{position:relative;display:inline-block;width:65px;height:26px}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;transition:0.4s;border-radius:26px;width:50px}.slider::before{content:"";position:absolute;height:20px;width:20px;left:3px;bottom:3px;background:linear-gradient(to bottom right,#555,#ccc);transition:0.4s;border-radius:50%}.switch input:checked+.slider{width:50px}.switch input:checked+.slider::before{transform:translateX(24px)}.reverb-box{background:#252424;padding:10px 15px 20px 15px;border-radius:40px;font-family:sans-serif;margin:0 auto}.reverb-box select{background-color:#252424;color:gold;border:2px solid #555;border-radius:8px;padding:10px 16px;font-weight:700;font-family:Arial,Helvetica,sans-serif;font-size:14px;outline:none;transition:background-color 0.3s,color 0.3s;width:95px}.ptpiano-wrapper{position:relative;min-height:300px;background:#fff0}.ptpiano-loader{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:10}.ptpiano-loader p{margin-top:15px;font-size:14px;font-weight:700;color:#333}.spinner{width:40px;height:40px;border:4px solid #ddd;border-top:4px solid cyan;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{100%{transform:rotate(360deg)}}.popup-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgb(0 0 0 / .75);display:none;justify-content:center;align-items:center;z-index:9999;pointer-events:all}.popup-content{background:#252424;padding:25px 30px;color:#fff;border-radius:12px;text-align:center;max-width:350px;box-shadow:0 10px 25px rgb(0 0 0 / .3);animation:fadeInScale 0.3s ease-in-out;font-family:'Segoe UI',sans-serif}.popup-content h3{margin-top:0;color:#555}.popup-content p{color:#555;margin:15px 0}.popup-content button{background-color:#3a7afe;color:#fff;border:none;padding:10px 18px;font-size:14px;border-radius:6px;cursor:pointer}.popup-content button:hover{background-color:#245fd3}@media screen and (max-width:1280px){.content-wrapper{padding:5px}header{flex-direction:column}header :where(h2,.column){margin-bottom:13px}.piano-header{width:170px!important}.piano-speaker{display:none}.col-center{grid-column:1 / -1;width:100%;padding-left:0;align-items:center}#played-notes{width:120px!important}.content-wrapper .control{display:block!important}.chord-group{display:block!important;margin:0!important}.chord-option select{display:block;width:100%!important;margin-left:0}.chord-option::before{display:none}.chord-label{display:none}.left-column{width:99%!important}.columnboxpiano{flex-direction:column;align-items:center}.piano-keys .black{height:100px;width:44px;margin:0 -20px 0 -20px}.piano-keys .white{height:180px;width:70px}.piano-keys{display:flex;justify-content:space-between;flex-wrap:nowrap;margin:0!important;padding:0 5px}.piano-keys .white{width:9.5vw;height:140px}.piano-keys .black{width:5vw;height:100px;margin:0 -2.5vw}.right-column{width:98%!important;padding:10px 0}canvas#equalizer{width:95%!important;height:auto!important}.piano-keys .key span{font-size:10px}}
Note: See TracChangeset for help on using the changeset viewer.