(function(){ 'use strict'; /* ============================================ 定数・データ ============================================ */ var MIDI_START = 36; // C2 var MIDI_END = 84; // C6 var NOTE_NAMES = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']; var MALE_TALK_LOW = 40; // E2 var MALE_TALK_HIGH = 53; // F3 var FEMALE_TALK_LOW = 55; // G3 var FEMALE_TALK_HIGH = 64; // E4 function midiToName(m){ return NOTE_NAMES[m%12]+(Math.floor(m/12)-1); } function midiToFreq(m){ return 440*Math.pow(2,(m-69)/12); } // DAM Top 100 [rank, title, artist, lowMidi, chestMidi, falsettoMidi(0=none), suitability] var SONGS=[ [1,"ライラック","Mrs. GREEN APPLE",50,71,73,"男性"], [2,"怪獣の花唄","Vaundy",50,71,74,"高難度"], [3,"残酷な天使のテーゼ","高橋洋子",58,72,0,"女性"], [4,"サウダージ","ポルノグラフィティ",59,68,0,"女性"], [5,"マリーゴールド","あいみょん",54,71,0,"女性"], [6,"さよならエレジー","菅田将暉",49,68,0,"男性"], [7,"ドライフラワー","優里",55,69,72,"男性"], [8,"かわいいだけじゃだめですか?","CUTIE STREET",59,76,75,"女性"], [9,"ダーリン","Mrs. GREEN APPLE",46,73,69,"男性"], [10,"小さな恋のうた","MONGOL800",46,68,0,"男性"], [11,"水平線","back number",50,67,72,"男性"], [12,"ケセラセラ","Mrs. GREEN APPLE",49,73,77,"高難度"], [13,"高嶺の花子さん","back number",52,71,74,"男性"], [14,"奏(かなで)","スキマスイッチ",50,70,0,"男性"], [15,"点描の唄","Mrs. GREEN APPLE",57,74,79,"女性"], [16,"チェリー","スピッツ",52,69,0,"男性"], [17,"366日","HY",52,77,0,"高難度"], [18,"シングルベッド","シャ乱Q",49,68,0,"男性"], [19,"晩餐歌","tuki.",56,73,78,"女性"], [20,"青と夏","Mrs. GREEN APPLE",51,73,76,"高難度"], [21,"ひまわりの約束","秦基博",51,70,70,"男性"], [22,"丸の内サディスティック","椎名林檎",58,79,0,"女性"], [23,"チャンカパーナ","NEWS",50,71,0,"男性"], [25,"最後の雨","中西保志",47,69,0,"男性"], [26,"Story","AI",55,72,0,"女性"], [27,"Soranji","Mrs. GREEN APPLE",48,71,78,"高難度"], [28,"ハナミズキ","一青窈",56,71,73,"女性"], [29,"恋人ごっこ","マカロニえんぴつ",53,70,73,"男性"], [30,"大阪LOVER","DREAMS COME TRUE",58,74,0,"女性"], [31,"糸","中島みゆき",53,70,0,"男性"], [32,"世界が終るまでは…","WANDS",52,69,0,"男性"], [33,"愛をこめて花束を","Superfly",55,77,0,"女性"], [34,"キセキ","GReeeeN",55,70,0,"高難度"], [35,"Lemon","米津玄師",47,71,71,"男性"], [36,"Bling-Bang-Bang-Born","Creepy Nuts",45,66,0,"男性"], [37,"カブトムシ","aiko",56,72,77,"女性"], [38,"幾億光年","Omoinotake",50,73,78,"高難度"], [39,"アイノカタチ","MISIA",56,75,0,"女性"], [40,"イケナイ太陽","ORANGE RANGE",50,72,0,"男性"], [41,"クリスマスソング","back number",47,69,73,"高難度"], [42,"島人ぬ宝","BEGIN",48,65,0,"男性"], [43,"怪獣","サカナクション",54,70,71,"男性"], [44,"Bunny Girl","AKASAKI",48,64,0,"男性"], [45,"歌うたいのバラッド","斉藤和義",45,69,69,"男性"], [46,"気まぐれロマンティック","いきものがかり",57,71,74,"女性"], [47,"僕のこと","Mrs. GREEN APPLE",48,72,79,"男性"], [48,"シャルル","バルーン",50,73,0,"男性"], [49,"シンデレラボーイ","Saucy Dog",52,73,76,"高難度"], [50,"花束のかわりにメロディーを","清水翔太",51,68,73,"男性"], [51,"Pretender","Official髭男dism",51,72,73,"高難度"], [52,"コイスルオトメ","いきものがかり",59,73,73,"女性"], [53,"メロディー","玉置浩二",49,66,66,"男性"], [54,"I LOVE YOU","尾崎豊",52,66,69,"男性"], [55,"白い恋人達","桑田佳祐",50,67,71,"男性"], [56,"3月9日","レミオロメン",48,67,0,"男性"], [57,"チェックのワンピース","back number",51,68,0,"男性"], [58,"アゲハ蝶","ポルノグラフィティ",55,68,0,"男性"], [59,"IRIS OUT","米津玄師",44,69,71,"男性"], [60,"ハレンチ","ちゃんみな",52,71,0,"男性"], [61,"はいよろこんで","こっちのけんと",50,66,0,"男性"], [62,"虹","菅田将暉",48,69,0,"男性"], [63,"津軽海峡・冬景色","アンジェラ・アキ",56,75,0,"女性"], [64,"インフェルノ","Mrs. GREEN APPLE",40,71,76,"男性"], [65,"倍倍FIGHT!","CANDY TUNE",56,74,0,"女性"], [66,"タッチ","岩崎良美",57,71,0,"女性"], [67,"栄光の架橋","ゆず",47,69,0,"男性"], [68,"クスシキ","Mrs. GREEN APPLE",47,69,77,"男性"], [69,"アイドル","YOASOBI",54,74,78,"女性"], [70,"First Love","宇多田ヒカル",52,75,77,"高難度"], [71,"TSUNAMI","サザンオールスターズ",45,70,74,"男性"], [72,"粉雪","レミオロメン",47,69,69,"男性"], [73,"CITRUS","Da-iCE",53,73,74,"女性"], [74,"HANABI","Mr.Children",44,69,0,"男性"], [75,"雪の華","中島美嘉",54,73,75,"女性"], [76,"わたしの一番かわいいところ","FRUITS ZIPPER",55,73,73,"女性"], [77,"DAN DAN 心魅かれてく","FIELD OF VIEW",44,69,0,"男性"], [78,"残響散歌","Aimer",56,73,75,"女性"], [79,"猫","DISH//",48,70,0,"男性"], [80,"花束","back number",45,70,72,"男性"], [81,"ただ君に晴れ","ヨルシカ",50,75,0,"女性"], [82,"裸の心","あいみょん",53,73,75,"女性"], [83,"炎","LiSA",54,76,76,"女性"], [84,"ヒロイン","back number",50,71,71,"男性"], [85,"APT.","ROSÉ & Bruno Mars",58,72,70,"女性"], [86,"ダンスホール","Mrs. GREEN APPLE",57,71,78,"女性"], [87,"I wonder","Da-iCE",46,71,75,"男性"], [88,"愛唄","GReeeeN",51,72,0,"高難度"], [89,"未来予想図 Ⅱ","DREAMS COME TRUE",53,75,0,"女性"], [90,"魔法の絨毯","川崎鷹也",49,68,0,"男性"], [92,"天体観測","BUMP OF CHICKEN",44,68,0,"男性"], [93,"時の流れに身をまかせ","テレサ・テン",55,70,74,"女性"], [94,"眠り姫","SEKAI NO OWARI",50,65,0,"男性"], [95,"紅蓮華","LiSA",52,74,79,"高難度"], [96,"Love so sweet","嵐",51,69,0,"男性"], [97,"ビリミリオン","優里",50,70,72,"男性"], [98,"115万キロのフィルム","Official髭男dism",46,72,0,"高難度"], [99,"ロビンソン","スピッツ",54,71,73,"女性"], [100,"真夏の果実","サザンオールスターズ",45,69,71,"男性"] ]; // DAM ボカロランキング [rank, title, artist, lowMidi, highMidi, 0(no falsetto), ""] // 出典: merged-data0317.csv (50曲) + Web調査 (50曲) var SONGS_VOCALOID=[ [1,"シャルル","バルーン",49,82,0,""], [2,"モニタリング","DECO*27",69,77,0,""], [3,"少女レイ","みきとP",69,74,0,""], [4,"酔いどれ知らず","Kanaria",54,76,0,""], [5,"千本桜","WhiteFlame feat.初音ミク",55,76,0,""], [6,"テトリス","柊マグネタイト",71,78,0,""], [7,"ヒバナ","DECO*27",71,74,0,""], [8,"KING","Kanaria",55,79,0,""], [9,"ロキ","みきとP",71,76,0,""], [10,"ロミオとシンデレラ","doriko feat.初音ミク",56,77,0,""], [11,"天ノ弱","164 feat.GUMI",69,79,0,""], [12,"アスノヨゾラ哨戒班","Orangestar feat.IA",52,78,0,""], [13,"ブリキノダンス","日向電工",67,84,0,""], [14,"命に嫌われている","カンザキイオリ",55,79,0,""], [15,"からくりピエロ","40mP feat.初音ミク",53,81,0,""], [16,"神っぽいな","ピノキオピー",69,75,0,""], [17,"妄想感傷代償連盟","DECO*27",70,75,0,""], [18,"恋愛裁判","40mP feat.初音ミク",51,68,0,""], [19,"砂の惑星","ハチ feat.初音ミク",53,68,0,""], [20,"ロウワー","ぬゆり",61,79,0,""], [21,"ヴァンパイア","DECO*27",71,80,0,""], [22,"ロストワンの号哭","Neru feat.鏡音リン",71,95,0,""], [23,"右肩の蝶","のりぴー feat.鏡音レン",56,77,0,""], [24,"オーバーライド","吉田夜世",56,73,0,""], [25,"高音厨音域テスト","木村わいP feat.初音ミク",69,80,0,""], [26,"夜もすがら君想ふ","TOKOTOKO(西沢さんP) feat.GUMI",56,73,0,""], [27,"夜明けと蛍","n-buna feat.初音ミク",57,68,0,""], [28,"脳漿炸裂ガール","れるりり feat.初音ミク&GUMI",60,75,0,""], [29,"ラヴィ","すりぃ",55,95,0,""], [30,"ゴーストルール","DECO*27",69,78,0,""], [31,"抜錨","ナナホシ管弦楽団 feat.巡音ルカ",55,94,0,""], [32,"テレパシ","DECO*27",55,74,0,""], [33,"エゴロック","すりぃ feat.鏡音レン",55,79,0,""], [34,"乙女解剖","DECO*27",71,85,0,""], [35,"サマータイムレコード","じん(自然の敵P) feat.IA",52,78,0,""], [36,"テレキャスタービーボーイ","すりぃ feat.鏡音レン",63,80,0,""], [37,"メランコリック","Junky feat.鏡音リン",60,75,0,""], [38,"ヴィラン","てにをは feat.flower",69,73,0,""], [39,"地球最後の告白を","kemu feat.GUMI",53,79,0,""], [40,"六兆年と一夜物語","kemu feat.IA",69,78,0,""], [41,"メルト","supercell feat.初音ミク",69,93,0,""], [42,"マトリョシカ","ハチ feat.初音ミク&GUMI",61,76,0,""], [43,"グッバイ宣言","Chinozo",60,84,0,""], [44,"ダイダイダイダイダイキライ","雨良 Amala",70,77,0,""], [45,"だれかの心臓になれたなら","ユリイ・カノン",70,84,0,""], [46,"強風オールバック","ゆこぴ",55,83,0,""], [47,"ハッピーシンセサイザ","EasyPop feat.巡音ルカ&GUMI",55,68,0,""], [48,"回る空うさぎ","Orangestar",49,77,0,""], [49,"神のまにまに","れるりり feat.初音ミク&鏡音リン&GUMI",56,75,0,""], [50,"アンノウン・マザーグース","wowaka",42,81,0,""], [51,"ルカルカ★ナイトフィーバー","SAM(samfree)",63,75,0,""], [52,"とても素敵な六月でした","Eight feat.初音ミク",62,82,0,""], [53,"初音ミクの消失","cosMo@暴走P feat.初音ミク",70,80,0,""], [54,"ノンブレス・オブリージュ","ピノキオピー",69,84,0,""], [55,"D/N/A","Azari",62,76,0,""], [56,"雨とペトラ","バルーン",53,82,0,""], [57,"ベノム","かいりきベア",61,80,0,""], [58,"コールボーイ","syudou",64,80,0,""], [59,"吉原ラメント","亜沙 feat.重音テト",53,83,0,""], [60,"ジャンキーナイトタウンオーケストラ","すりぃ",69,77,0,""], [61,"太陽系デスコ","ナユタン星人",60,84,0,""], [62,"いーあるふぁんくらぶ","ミキト(みきとP) feat.GUMI&鏡音リン",70,72,0,""], [63,"エンヴィーベイビー","Kanaria",48,68,0,""], [64,"メズマライザー","サツキ",56,86,0,""], [65,"デリヘル呼んだら君が来た","ナナホシ管弦楽団 feat.初音ミク&IA",60,74,0,""], [66,"のだ","大漠波新",55,75,0,""], [67,"DAYBREAK FRONTLINE","Orangestar",55,93,0,""], [68,"東京テディベア","Neru feat.鏡音リン",62,94,0,""], [69,"ローリンガール","wowaka feat.初音ミク",61,78,0,""], [70,"悪魔の踊り方","キタニタツヤ",58,67,0,""], [71,"モザイクロール","DECO*27",71,75,0,""], [72,"パンダヒーロー","ハチ feat.GUMI",71,79,0,""], [73,"あの夏が飽和する","カンザキイオリ",62,93,0,""], [74,"ウミユリ海底譚","n-buna feat.初音ミク",55,76,0,""], [75,"あなたの夜が明けるまで","傘村トータ",62,95,0,""], [76,"ワールドイズマイン","supercell feat.初音ミク",56,75,0,""], [77,"カゲロウデイズ","じん(自然の敵P) feat.初音ミク",71,77,0,""], [78,"独りんぼエンヴィー","koyori(電ポルP) feat.初音ミク",69,75,0,""], [79,"フィクサー","ぬゆり feat.flower",66,85,0,""], [80,"メーベル","バルーン",51,73,0,""], [81,"ダーリンダンス","かいりきベア",54,72,0,""], [82,"心做し","蝶々P feat.GUMI",48,81,0,""], [83,"混沌ブギ","jon-YAKITORY",55,80,0,""], [84,"弱虫モンブラン","DECO*27",69,72,0,""], [85,"花瓶に触れた","バルーン",67,95,0,""], [86,"チェリーポップ","DECO*27",69,75,0,""], [87,"Surges","Orangestar feat.IA&初音ミク",53,93,0,""], [88,"エイリアンエイリアン","ナユタン星人",60,84,0,""], [89,"ジェヘナ","wotaku",69,80,0,""], [90,"ジレンマ","DECO*27",57,68,0,""], [91,"化けの花","なきそ",62,72,0,""], [92,"いますぐ輪廻","なきそ",55,78,0,""], [93,"Blessing","halyosy",55,78,0,""], [94,"転生林檎","ピノキオピー",60,75,0,""], [95,"Calc.","ジミーサムP feat.初音ミク",54,78,0,""], [96,"夜咄ディセイブ","じん(自然の敵P) feat.IA",69,74,0,""], [97,"ビターチョコデコレーション","syudou",69,74,0,""], [98,"深海少女","ゆうゆ feat.初音ミク",60,78,0,""], [99,"帝国少女","R Sound Design",59,66,0,""], [100,"妄想税","DECO*27",64,75,0,""] ]; function getActiveSongs(){ return state.songMode === 'vocaloid' ? SONGS_VOCALOID : SONGS; } /* ============================================ 状態管理 ============================================ */ var state = { currentNote: null, // 最後にタップした鍵盤のMIDI番号 lowest: null, // MIDI number chest: null, falsetto: null, diagnosed: false, showCount: 5, // 表示曲数 filter: 'all', searchQuery: '', gender: null, songMode: 'normal', // 'normal' | 'vocaloid' adjustments: [], // 計算済みキー調整 adjustmentsVocal: [] // ボカロ用 }; /* ============================================ Web Audio API - ピアノ音源 ============================================ */ var audioCtx = null; function initAudio(){ if(!audioCtx){ audioCtx = new (window.AudioContext||window.webkitAudioContext)(); } if(audioCtx.state==='suspended') audioCtx.resume(); } function playNote(midi){ initAudio(); var freq = midiToFreq(midi); var now = audioCtx.currentTime; // Piano-like synthesis: fundamental + harmonics with decay var harmonics = [1, 2, 3, 4, 5, 6]; var amps = [1, 0.5, 0.3, 0.15, 0.08, 0.04]; var gain = audioCtx.createGain(); gain.connect(audioCtx.destination); // Higher notes decay faster var decayTime = Math.max(0.3, 1.5 - (midi - 36) * 0.02); gain.gain.setValueAtTime(0, now); gain.gain.linearRampToValueAtTime(0.25, now + 0.008); gain.gain.exponentialRampToValueAtTime(0.001, now + decayTime); harmonics.forEach(function(h, i){ var osc = audioCtx.createOscillator(); var hGain = audioCtx.createGain(); osc.type = 'sine'; osc.frequency.setValueAtTime(freq * h, now); hGain.gain.setValueAtTime(amps[i], now); osc.connect(hGain); hGain.connect(gain); osc.start(now); osc.stop(now + decayTime + 0.05); }); } /* ============================================ ピアノ鍵盤の構築 ============================================ */ function buildPiano(){ var container = document.getElementById('vrc-piano'); if(!container) return; container.innerHTML = ''; for(var m = MIDI_START; m <= MIDI_END; m++){ var noteIdx = m % 12; var isBlack = [1,3,6,8,10].indexOf(noteIdx) !== -1; var key = document.createElement('div'); key.className = isBlack ? 'vrc-key-black' : 'vrc-key-white'; key.dataset.midi = m; if(!isBlack){ var name = midiToName(m); // Show note name on white keys at C and at specific notes if(noteIdx === 0 || noteIdx === 4 || noteIdx === 7){ key.textContent = name; } } key.addEventListener('pointerdown', function(e){ e.preventDefault(); var mid = parseInt(this.dataset.midi); onKeyPress(mid, this); }); container.appendChild(key); } } function onKeyPress(midi, el){ playNote(midi); // Remove previous current highlight var prev = document.querySelector('#vrc-piano .current'); if(prev) prev.classList.remove('current'); // Persist highlight on tapped key el.classList.add('current'); state.currentNote = midi; // Update note display updateNoteDisplay(midi); } /* ============================================ 音名表示 ============================================ */ function updateNoteDisplay(midi){ var display = document.getElementById('vrc-note-display'); var name = midiToName(midi); var hint = ''; if(midi >= MALE_TALK_LOW && midi <= MALE_TALK_HIGH){ hint = '=男性の話し声の高さ'; } else if(midi >= FEMALE_TALK_LOW && midi <= FEMALE_TALK_HIGH){ hint = '=女性の話し声の高さ'; } display.innerHTML = '' + name + '' + (hint ? '' + hint + '' : ''); } /* ============================================ 音域設定 ============================================ */ function setRangeValue(mode, midi){ state[mode] = midi; var name = midiToName(midi); var valEl = document.getElementById('vrc-val-' + mode); valEl.textContent = name; var btn = document.getElementById('vrc-btn-' + mode); btn.classList.add('has-value'); // Validation if(state.lowest !== null && state.chest !== null && state.chest < state.lowest){ state.chest = null; document.getElementById('vrc-val-chest').textContent = ''; document.getElementById('vrc-btn-chest').classList.remove('has-value'); } if(state.chest !== null && state.falsetto !== null && state.falsetto < state.chest){ // falsetto can be lower than chest in some cases, allow it } updatePianoHighlight(); checkDiagnoseReady(); } function updatePianoHighlight(){ var keys = document.querySelectorAll('#vrc-piano > div'); keys.forEach(function(k){ k.classList.remove('in-range-chest','in-range-falsetto','is-lowest','is-chest','is-falsetto','current'); var m = parseInt(k.dataset.midi); if(state.lowest !== null && m === state.lowest) k.classList.add('is-lowest'); if(state.chest !== null && m === state.chest) k.classList.add('is-chest'); if(state.falsetto !== null && m === state.falsetto) k.classList.add('is-falsetto'); if(state.lowest !== null && state.chest !== null){ if(m > state.lowest && m < state.chest) k.classList.add('in-range-chest'); } if(state.chest !== null && state.falsetto !== null){ if(m > state.chest && m < state.falsetto) k.classList.add('in-range-falsetto'); } }); } function checkDiagnoseReady(){ var btn = document.getElementById('vrc-diagnose-btn'); if(state.lowest !== null && state.chest !== null && state.falsetto !== null){ btn.classList.add('show'); } else { btn.classList.remove('show'); } } function resetAll(){ state.lowest = null; state.chest = null; state.falsetto = null; state.currentNote = null; state.diagnosed = false; state.showCount = 5; ['lowest','chest','falsetto'].forEach(function(m){ document.getElementById('vrc-val-' + m).textContent = ''; var btn = document.getElementById('vrc-btn-' + m); btn.classList.remove('has-value'); }); document.getElementById('vrc-diagnose-btn').classList.remove('show'); document.getElementById('vrc-results').classList.remove('show'); document.getElementById('vrc-songs').classList.remove('show'); document.getElementById('vrc-picks').classList.remove('show'); updatePianoHighlight(); var display = document.getElementById('vrc-note-display'); display.innerHTML = '鍵盤をタップして音を鳴らしてみましょう'; } /* ============================================ 診断 & キー調整計算 ============================================ */ function diagnose(){ if(state.lowest===null||state.chest===null||state.falsetto===null) return; state.diagnosed = true; // Calculate key adjustments for a song list function calcAll(songList){ return songList.map(function(s){ var shift = calcOptimalKey( {low:s[3], chest:s[4], falsetto:s[5]||s[4]}, {low:state.lowest, chest:state.chest, falsetto:state.falsetto} ); var songHigh0 = Math.max(s[4], s[5]||s[4]); var userHigh0 = Math.max(state.chest, state.falsetto); var ol0 = Math.max(0, Math.min(songHigh0, userHigh0) - Math.max(s[3], state.lowest)); var sw0 = songHigh0 - s[3]; var cov0 = sw0 > 0 ? ol0 / sw0 : 0; return { rank: s[0], title: s[1], artist: s[2], low: s[3], chest: s[4], falsetto: s[5], suit: s[6], shift: shift, absShift: Math.abs(shift), coverageAt0: cov0 }; }); } state.adjustments = calcAll(SONGS); state.adjustments.sort(function(a,b){ return a.rank - b.rank; }); state.adjustmentsVocal = calcAll(SONGS_VOCALOID); state.adjustmentsVocal.sort(function(a,b){ return a.rank - b.rank; }); showResults(); showPicks(); showSongs(); document.getElementById('vrc-results').scrollIntoView({behavior:'smooth', block:'start'}); } function calcOptimalKey(song, user){ var bestShift = 0; var bestScore = -999; var userHigh = Math.max(user.chest, user.falsetto); for(var k = -12; k <= 12; k++){ var sLow = song.low + k; var songHigh = Math.max(song.chest + k, (song.falsetto||song.chest) + k); // High notes above user's total range = critical var exceedAbove = Math.max(0, songHigh - userHigh); // Low notes below user's range = shift up to fix var exceedBelow = Math.max(0, user.low - sLow); var penalty = exceedAbove * 0.5 + exceedBelow * 0.2; // Prefer smaller shifts var shiftPenalty = Math.abs(k) * 0.02; var score = 1 - penalty - shiftPenalty; if(score > bestScore){ bestScore = score; bestShift = k; } } return bestShift; } /* ============================================ キー表示フォーマット(オク下/オク上対応) ============================================ */ function formatKeyShift(shift){ var displayShift = shift; var label = ''; if(shift < -6){ displayShift = shift + 12; label = 'オク下'; } else if(shift > 6){ displayShift = shift - 12; label = 'オク上'; } var text = displayShift === 0 ? '±0' : (displayShift > 0 ? '+'+displayShift : ''+displayShift); return { text: text, displayShift: displayShift, label: label, badgeClass: displayShift < 0 ? 'down' : (displayShift === 0 ? 'zero' : 'up') }; } /* ============================================ 結果表示 ============================================ */ function showResults(){ var el = document.getElementById('vrc-results'); el.classList.add('show'); var grid = document.getElementById('vrc-result-grid'); grid.innerHTML = '
最低音
' + midiToName(state.lowest) + '
' + '
地声最高音
' + midiToName(state.chest) + '
' + '
裏声最高音
' + midiToName(state.falsetto) + '
'; var rangeWidth = (state.falsetto || state.chest) - state.lowest; var summary = document.getElementById('vrc-result-summary'); var desc = ''; var rangePctR = Math.round(rangeWidth / 48 * 100); if(rangePctR >= 90){ desc = 'あなたの音域は平均よりもかなり広めです。幅広いジャンルの曲に対応できます。'; } else if(rangePctR >= 70){ desc = 'あなたの音域は平均よりも広めです。多くのポップスが歌いやすい音域を持っています。'; } else if(rangePctR >= 50){ desc = 'あなたの音域は平均よりもやや広めです。キー調整を活用すればさらに多くの曲が歌えます。'; } else if(rangePctR >= 30){ desc = 'あなたの音域は標準的です。キー調整を上手に使えばほとんどの曲に対応できます。'; } else { desc = 'あなたの音域はやや狭めです。キーを調整することで多くの曲が歌いやすくなります。'; } desc += '音域の幅は' + rangeWidth + '半音(約' + Math.round(rangeWidth/12*10)/10 + 'オクターブ)です。'; summary.innerHTML = desc; } function showSongs(){ var el = document.getElementById('vrc-songs'); el.classList.add('show'); renderSongTable(); } function getActiveAdjustments(){ return state.songMode === 'vocaloid' ? state.adjustmentsVocal : state.adjustments; } function renderSongTable(){ var body = document.getElementById('vrc-songs-body'); var filtered = getActiveAdjustments().filter(function(s){ // Filter if(state.filter === 'male' && s.suit !== '男性') return false; if(state.filter === 'female' && s.suit !== '女性') return false; // Search if(state.searchQuery){ var q = state.searchQuery.toLowerCase(); if(s.title.toLowerCase().indexOf(q)===-1 && s.artist.toLowerCase().indexOf(q)===-1) return false; } return true; }); // Sort: 歌いやすい曲 = narrowest vocal range, others = popularity if(state.filter === 'easy'){ filtered.sort(function(a,b){ var aRange = (a.falsetto || a.chest) - a.low; var bRange = (b.falsetto || b.chest) - b.low; return aRange - bRange || a.rank - b.rank; }); } else { filtered.sort(function(a,b){ return a.rank - b.rank; }); } var show = state.searchQuery ? filtered.length : Math.min(state.showCount, filtered.length); var html = ''; for(var i = 0; i < show; i++){ var s = filtered[i]; var fmt = formatKeyShift(s.shift); var songRange = midiToName(s.low) + '〜' + midiToName(s.chest); if(s.falsetto) songRange += '(裏声' + midiToName(s.falsetto) + ')'; var octLabel = fmt.label ? '' + fmt.label + '' : ''; html += '' + '
' + s.title + '
' + '
' + s.artist + '
' + '' + '
' + fmt.text + '
' + octLabel + '' + '
' + songRange + '
' + ''; } body.innerHTML = html; var moreBtn = document.getElementById('vrc-show-more'); moreBtn.style.display = (show < filtered.length && !state.searchQuery) ? 'block' : 'none'; } /* ============================================ アルバムアートワーク(Apple Music) ============================================ */ var SONG_COVERS = { "ライラック":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/4c/3b/b2/4c3bb247-3be8-0c57-aa9a-7f1775a7b7a8/24UMGIM32931.rgb.jpg/300x300bb.jpg", "怪獣の花唄":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/8a/eb/75/8aeb7526-6fe4-a81a-5dce-c5d026e7f036/4547366655728.jpg/300x300bb.jpg", "残酷な天使のテーゼ":"https://is1-ssl.mzstatic.com/image/thumb/Music/c7/68/d7/mzi.anmgzqdl.jpg/300x300bb.jpg", "サウダージ":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/78/f2/bb/78f2bb53-bef0-9ab2-6cc2-7a89af8eb2ac/jacket_SRCL04901B00Z_550.jpg/300x300bb.jpg", "マリーゴールド":"https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/67/34/90/67349087-0609-2be4-4963-fd4682ae8c46/190295600341.jpg/300x300bb.jpg", "さよならエレジー":"https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/61/89/9e/61899ec0-432b-d07f-0f6d-04fb01572ecd/jacket_ESXX01814B00Z_550.jpg/300x300bb.jpg", "ドライフラワー":"https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/d2/23/07/d2230757-3f9c-fccd-3cc8-333f7be09716/4547366478655.jpg/300x300bb.jpg", "かわいいだけじゃだめですか?":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/71/a6/91/71a691bc-b5a6-7903-4b13-608611c2f2b3/4580789670411.jpg/300x300bb.jpg", "ダーリン":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/7b/b9/27/7bb92776-1f4a-06c6-e36e-de889f2b8620/25UMGIM01757.rgb.jpg/300x300bb.jpg", "小さな恋のうた":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/62/3b/85/623b858b-d88f-2c04-cb5d-4923e1d64190/mzi.beiflkay.tif/300x300bb.jpg", "水平線":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/bd/d6/8f/bdd68f1b-8588-3e91-faab-ab9d7ca35c2f/21UMGIM28078.rgb.jpg/300x300bb.jpg", "ケセラセラ":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/25/22/db/2522db04-1404-086a-c8a2-253484030b36/23UMGIM37150.rgb.jpg/300x300bb.jpg", "高嶺の花子さん":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/ad/35/1f/ad351f01-3b1e-e723-77db-3a7d88221e5e/00602577303753.rgb.jpg/300x300bb.jpg", "奏(かなで)":"https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/5f/e6/5a/5fe65a3b-98a0-b453-02a2-aad961438a39/00602557541564.rgb.jpg/300x300bb.jpg", "点描の唄":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/34/27/08/3427087f-2d39-4847-9b19-052dd3589014/18UMGIM36633.rgb.jpg/300x300bb.jpg", "チェリー":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/29/c0/30/29c030c7-ae9c-a201-ef47-bf9a8b2ed31a/00600406212191.rgb.jpg/300x300bb.jpg", "366日":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/bd/c1/f7/bdc1f77e-f4a1-3e8f-d9fe-9910be6a4196/mzi.gzufbkti.jpg/300x300bb.jpg", "シングルベッド":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/aa/d3/a4/aad3a4c4-b574-ed2d-416c-821773e3ed07/jacket_MHCL30151B00Z_550.jpg/300x300bb.jpg", "晩餐歌":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/67/03/c9/6703c973-c9da-1bd8-cc81-fe315b951231/4582649065306.jpg/300x300bb.jpg", "青と夏":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/34/27/08/3427087f-2d39-4847-9b19-052dd3589014/18UMGIM36633.rgb.jpg/300x300bb.jpg", "ひまわりの約束":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/84/c7/0b/84c70b45-4db3-72db-4f3c-cbffe6b2cefa/00602557538274.rgb.jpg/300x300bb.jpg", "丸の内サディスティック":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/bd/da/b4/bddab4d2-176e-6438-76dc-54bd4eac3914/18UMGIM22257.rgb.jpg/300x300bb.jpg", "チャンカパーナ":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/92/46/0f/92460f79-c5d2-ee56-34bd-ded18519fb67/4517331087649.jpg/300x300bb.jpg", "最後の雨":"https://is1-ssl.mzstatic.com/image/thumb/Music/v4/39/ae/e4/39aee461-6a35-41d8-b4ba-be4da7d13f67/COKM_31561.jpg/300x300bb.jpg", "Story":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/a6/e0/7e/a6e07e13-7bb3-2cc7-0f36-45ca28138d8e/06UMGIM42910.rgb.jpg/300x300bb.jpg", "Soranji":"https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/e1/ec/d4/e1ecd4b4-4f2f-c49e-fa95-958c6b4cf7ab/22UM1IM16537.rgb.jpg/300x300bb.jpg", "ハナミズキ":"https://is1-ssl.mzstatic.com/image/thumb/Music128/v4/b4/ae/05/b4ae053f-54ad-a984-f0bb-84f35c7c1c73/00600406609519.rgb.jpg/300x300bb.jpg", "恋人ごっこ":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/87/88/05/8788059e-117b-439e-f3f1-e0e2da15db31/bigup13058482.jpg/300x300bb.jpg", "大阪LOVER":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/1b/06/4b/1b064b9d-4912-9a2c-94fc-4caadf42fbab/00044002558121.rgb.jpg/300x300bb.jpg", "糸":"https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/ad/d7/78/add7785f-da7a-26c9-2157-1c6057bca0bb/YCCI10481P000000.jpg/300x300bb.jpg", "世界が終るまでは…":"https://is1-ssl.mzstatic.com/image/thumb/Music112/v4/cc/2f/5c/cc2f5c71-d976-d503-f107-ef0f71a14b84/wands-0121.jpg/300x300bb.jpg", "愛をこめて花束を":"https://is1-ssl.mzstatic.com/image/thumb/Music/a8/b4/a0/mzi.snoeojdw.jpg/300x300bb.jpg", "キセキ":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/59/71/a5/5971a58d-9b81-1c64-195e-9e896c804d06/00044002897312.rgb.jpg/300x300bb.jpg", "Lemon":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/86/b0/9d/86b09d63-367a-563a-1e24-d5d62c220ac8/jacket_SRCL09749B00Z_550.jpg/300x300bb.jpg", "Bling-Bang-Bang-Born":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/12/81/dc/1281dc28-48e6-5ff7-642d-6cf4d487d9e0/4547366660890.jpg/300x300bb.jpg", "カブトムシ":"https://is1-ssl.mzstatic.com/image/thumb/Music123/v4/bb/b1/26/bbb12681-ba77-f107-2a16-c684f685b464/dj.jqehhfti.jpg/300x300bb.jpg", "幾億光年":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/7e/e5/e6/7ee5e6f7-9c93-f121-fca0-e371dbce8f6e/4547366665246.jpg/300x300bb.jpg", "アイノカタチ":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/b8/0d/73/b80d73a6-3519-9990-837b-d3f009fa55df/jacket_BVXX01113B00Z_550.jpg/300x300bb.jpg", "イケナイ太陽":"https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/a9/9d/09/a99d0919-788a-4f0f-0c7b-045adeccbb45/jacket_SRCL06825B00Z_550.jpg/300x300bb.jpg", "クリスマスソング":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/29/ec/e8/29ece87b-ca51-50eb-30a5-6b3efdeb8767/00602577303920.rgb.jpg/300x300bb.jpg", "島人ぬ宝":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/b8/aa/55/b8aa55b9-c925-bdbc-50c4-cb98c5313657/cover.jpg/300x300bb.jpg", "怪獣":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/44/35/c7/4435c703-3647-654b-16a7-ab74885f71da/VEATP-43484.jpg/300x300bb.jpg", "Bunny Girl":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/f6/6e/c2/f66ec203-aee5-74dc-c8e3-1bd9b2134d49/24UM1IM31705.rgb.jpg/300x300bb.jpg", "歌うたいのバラッド":"https://is1-ssl.mzstatic.com/image/thumb/Music118/v4/d2/0e/85/d20e854b-865c-6c54-f4ac-a0500dbcef6a/VEATP-34575.jpg/300x300bb.jpg", "気まぐれロマンティック":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/49/82/a0/4982a066-6dbf-5482-d68b-aa154848ee6c/jacket_ESCL03139B00Z_550.jpg/300x300bb.jpg", "僕のこと":"https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/37/30/a9/3730a9f0-50d3-e4e1-9f4d-620b30380414/18UMGIM80785.rgb.jpg/300x300bb.jpg", "シャルル":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/06/fa/ea/06faea93-525a-ed28-5521-a3774a7afc35/4589686423939_cover.jpg/300x300bb.jpg", "シンデレラボーイ":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/d9/5c/85/d95c85ae-0227-9b9b-0d6d-ae1e45bb1ee5/25UMGIM98719.rgb.jpg/300x300bb.jpg", "花束のかわりにメロディーを":"https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/d1/3e/e3/d13ee389-2cbc-62d5-de57-7945db378685/jacket_SRCL08919B00Z_550.jpg/300x300bb.jpg", "Pretender":"https://is1-ssl.mzstatic.com/image/thumb/Music113/v4/9c/7d/88/9c7d883d-4477-bf68-f56f-a726030a63a2/PCCA_04822.jpg/300x300bb.jpg", "コイスルオトメ":"https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/26/e1/47/26e147d9-3f35-203f-ef83-9d8cf0a62b8b/jacket_ESCL03528B00Z_550.jpg/300x300bb.jpg", "メロディー":"https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/9a/1f/95/9a1f95f7-260c-7399-6c07-920cf889d452/jacket_MHXX00952B00Z_550.jpg/300x300bb.jpg", "I LOVE YOU":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/6c/6a/4d/6c6a4d8b-c0c9-7d3b-c9c0-1a9c0c7c5f4b/jacket_SRXX01408B00Z_550.jpg/300x300bb.jpg", "白い恋人達":"https://is1-ssl.mzstatic.com/image/thumb/Music49/v4/61/c2/53/61c253e3-f57d-006a-a8a6-a2a2710ec0ed/VEATP-33298.jpg/300x300bb.jpg", "3月9日":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/79/8b/74/798b74e3-d88b-6107-48cb-1c03a7f86dba/VEATP-44545.jpg/300x300bb.jpg", "チェックのワンピース":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/26/b6/e7/26b6e7e2-1cbb-4dde-edfb-e44e1f881cbd/00602577303739.rgb.jpg/300x300bb.jpg", "アゲハ蝶":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/74/3f/9c/743f9c6d-873f-07b5-6dd9-b1e3e87cee7e/jacket_SEXX00739B00Z_550.jpg/300x300bb.jpg", "IRIS OUT":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/e0/f9/f1/e0f9f1f3-a088-b28d-6760-a28accabc705/4547366775181.jpg/300x300bb.jpg", "ハレンチ":"https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/bd/c0/80/bdc08023-823d-b74c-0b58-e161fe8ae68b/190296458705.jpg/300x300bb.jpg", "はいよろこんで":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/0e/80/f2/0e80f216-59c5-614e-ba6b-d16645370b06/4571640152092_cover.jpg/300x300bb.jpg", "虹":"https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/2e/b0/3e/2eb03e07-08bf-df9e-2815-1b88f8146e79/4547366482928.jpg/300x300bb.jpg", "津軽海峡・冬景色":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/fc/f9/5a/fcf95aee-2619-52fc-66a1-89682dec2008/cover.jpg/300x300bb.jpg", "インフェルノ":"https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/d6/9e/54/d69e54ca-2d82-f291-d745-9a706aa26940/19UMGIM59475.rgb.jpg/300x300bb.jpg", "倍倍FIGHT!":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/dc/e5/64/dce56488-6cca-c862-c407-fc93ff38e7b9/4580789631009.jpg/300x300bb.jpg", "タッチ":"https://is1-ssl.mzstatic.com/image/thumb/Music3/v4/89/3b/3c/893b3cf3-ecbe-f2cb-adc9-323f1d3898c6/PCSP_01801_itunes.png/300x300bb.jpg", "栄光の架橋":"https://is1-ssl.mzstatic.com/image/thumb/Music/24/05/c4/mzi.wyjzyljh.jpg/300x300bb.jpg", "クスシキ":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/a0/cc/26/a0cc2636-c5ce-3058-fe52-7b65b90e8ec1/25UMGIM77456.rgb.jpg/300x300bb.jpg", "アイドル":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/3a/17/eb/3a17eb30-eacb-82eb-51df-d1321dbb55bc/197188492205.jpg/300x300bb.jpg", "First Love":"https://is1-ssl.mzstatic.com/image/thumb/Music128/v4/d1/a6/81/d1a681b9-aa68-6148-5a50-69fd4c95cc37/00602567241966.rgb.jpg/300x300bb.jpg", "TSUNAMI":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/79/e7/70/79e7709a-96a4-9029-e22c-f9252575a6ec/VEATP-30872.jpg/300x300bb.jpg", "粉雪":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/36/1b/f2/361bf2e3-ae78-e0d9-5092-d4c428e5a9fa/VEATP-44550.jpg/300x300bb.jpg", "CITRUS":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/06/a1/d8/06a1d861-418e-3fb1-e873-356f7f49090b/ANTCD-A0000002767.jpg/300x300bb.jpg", "HANABI":"https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/05/dd/70/05dd70e7-7e34-1836-4683-ff416d11a35c/dj.xwkpljqa.jpg/300x300bb.jpg", "雪の華":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/7d/1d/81/7d1d818e-d062-6c58-b977-8c389d1388c3/jacket_AICL01494B00Z_550.jpg/300x300bb.jpg", "わたしの一番かわいいところ":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/63/24/b6/6324b6d9-8535-8783-3a2a-bc838dd45826/4582467702803.jpg/300x300bb.jpg", "DAN DAN 心魅かれてく":"https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/62/b3/40/62b340c8-6c0c-168b-3ccc-ed80a0297312/859759846113_cover.png/300x300bb.jpg", "残響散歌":"https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/c9/40/9e/c9409e84-c0ea-c389-3be3-2343ec3dfb3b/4547366539806.jpg/300x300bb.jpg", "猫":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/f8/e0/c3/f8e0c344-3035-ce6c-aaf4-9efd2cfb8a4b/jacket_SRXX02423B00Z_550.jpg/300x300bb.jpg", "花束":"https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/40/e5/93/40e59322-1405-fbd9-81e0-c37f887d7133/00602577303814.rgb.jpg/300x300bb.jpg", "ただ君に晴れ":"https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/e3/e5/7a/e3e57a00-ed2d-69d6-bf00-347d7c37f3bd/PA00074572_0_90261_jacket.jpg/300x300bb.jpg", "裸の心":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/85/0b/1b/850b1b4c-f529-6828-4b2b-a5a187ec61c6/190295235017.jpg/300x300bb.jpg", "炎":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/88/ce/67/88ce6774-3358-e238-5244-1b0788adea50/4547366475562.jpg/300x300bb.jpg", "ヒロイン":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/5d/d1/f0/5dd1f0aa-4b50-e6b1-73b1-fb740989afba/00602577303906.rgb.jpg/300x300bb.jpg", "APT.":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/2d/1a/7d/2d1a7d91-587e-0ceb-d434-327bd66d9e86/075679628312.jpg/300x300bb.jpg", "ダンスホール":"https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/b7/20/05/b7200500-e97d-8c79-7cf2-99a6fb1aaf4d/22UMGIM50592.rgb.jpg/300x300bb.jpg", "I wonder":"https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/b4/32/b8/b432b806-4718-07d6-e37f-59ee11893da4/ANTCD-A0000013226.jpg/300x300bb.jpg", "愛唄":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/d5/d2/6d/d5d26d86-26db-367e-5f6a-ace2e0a9e9ff/00028945075099.rgb.jpg/300x300bb.jpg", "未来予想図 Ⅱ":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/7b/7c/36/7b7c36bb-eb3e-52bc-bbc4-0301e448ba97/jacket_ESCB01018B00Z_550.jpg/300x300bb.jpg", "魔法の絨毯":"https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/af/1d/c2/af1dc23c-09fb-3f77-4288-27d15e60bb00/190296596384.jpg/300x300bb.jpg", "天体観測":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/50/85/26/50852674-2973-742b-d4ea-8d0bae94f344/TFCC-87080WW.jpg/300x300bb.jpg", "時の流れに身をまかせ":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/61/fa/f1/61faf1ac-fb6c-e8c8-b053-14ff50b704e2/00044002896971.rgb.jpg/300x300bb.jpg", "眠り姫":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/7e/b4/76/7eb47679-4c56-9275-1a39-77ad820edb7f/TFCC-86389.jpg/300x300bb.jpg", "紅蓮華":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/b3/ae/3b/b3ae3bd0-47cc-6349-1d0d-a01928796a62/jacket_VVXX00432B00Z_550.jpg/300x300bb.jpg", "Love so sweet":"https://is1-ssl.mzstatic.com/image/thumb/Music113/v4/8e/10/2a/8e102abd-d981-e370-82db-2ae5c98baac3/194491537920.jpg/300x300bb.jpg", "ビリミリオン":"https://is1-ssl.mzstatic.com/image/thumb/Music112/v4/2b/b8/c9/2bb8c92c-9d9a-9463-958c-ec0d6ce60fb5/4547366600032.jpg/300x300bb.jpg", "115万キロのフィルム":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/40/e8/2d/40e82dfb-55b4-7016-1127-357ab78d3f7f/jk.jpg/300x300bb.jpg", "ロビンソン":"https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/9a/26/3b/9a263bc6-cebd-04df-c362-2a0868d277dd/00602557728743.rgb.jpg/300x300bb.jpg", "真夏の果実":"https://is1-ssl.mzstatic.com/image/thumb/Music5/v4/1d/85/cd/1d85cd11-48db-8ca2-8c58-ff0900a1bac1/VEATP-31058.jpg/300x300bb.jpg" }; /* ============================================ あなたにぴったりの曲 ============================================ */ function showPicks(){ var el = document.getElementById('vrc-picks'); var track = document.getElementById('vrc-picks-track'); el.classList.add('show'); // Sort by closest to original key (smallest absShift), then by rank state.picksSorted = getActiveAdjustments().slice().sort(function(a,b){ return a.absShift - b.absShift || a.rank - b.rank; }); state.picksShown = 5; renderPicks(); } function renderPicks(){ var track = document.getElementById('vrc-picks-track'); var items = state.picksSorted.slice(0, state.picksShown); var html = ''; items.forEach(function(s){ var fmt = formatKeyShift(s.shift); var badgeText = fmt.text; if(fmt.label) badgeText += ' ' + fmt.label; var badgeClass = fmt.badgeClass; var coverImg = SONG_COVERS[s.title] || ''; var coverHtml = coverImg ? '' + s.title + '' : '
' + s.title.charAt(0) + '
'; var appleUrl = 'https://music.apple.com/jp/search?term=' + encodeURIComponent(s.title + ' ' + s.artist); html += '
' + '
' + coverHtml + '
' + badgeText + '
' + '
' + '
' + '
' + s.title + '
' + '
' + s.artist + '
' + '
'; }); if(state.picksShown < state.picksSorted.length){ html += '
もっと見る →
'; } track.innerHTML = html; var moreBtn = document.getElementById('vrc-picks-more-btn'); if(moreBtn){ moreBtn.addEventListener('click', function(){ state.picksShown += 5; renderPicks(); }); } } /* ============================================ シードデータ & パーセンタイル ============================================ */ function seededRng(seed){ return function(){ seed = (seed * 16807) % 2147483647; return (seed - 1) / 2147483646; }; } function generateSeedData(){ var rng = seededRng(12345); var data = []; var norm = function(){ var u1 = rng(), u2 = rng(); return Math.sqrt(-2*Math.log(u1))*Math.cos(2*Math.PI*u2); }; var clamp = function(v,lo,hi){ return Math.max(lo, Math.min(hi, Math.round(v))); }; // Male: 300 entries for(var i=0;i<300;i++){ data.push({ g:'male', a: clamp(30+norm()*8, 15, 60), l: clamp(42+norm()*3, 36, 55), c: clamp(68+norm()*3, 58, 76), f: clamp(73+norm()*3, 63, 82) }); } // Female: 300 entries for(var j=0;j<300;j++){ data.push({ g:'female', a: clamp(30+norm()*8, 15, 60), l: clamp(55+norm()*3, 46, 65), c: clamp(73+norm()*3, 65, 80), f: clamp(77+norm()*3, 70, 84) }); } return data; } var SEED_DATA = generateSeedData(); // Load user-submitted data from WP (or localStorage fallback) var USER_DATA = []; try { var stored = localStorage.getItem('vrc_reports'); if(stored) USER_DATA = JSON.parse(stored); } catch(e){} function getAllData(){ return SEED_DATA.concat(USER_DATA); } function getPercentile(values, userValue, higherIsBetter){ var count = 0; for(var i=0;i userValue) count++; } return Math.round((count / values.length) * 100); } function calcStats(age, gender){ var allData = getAllData(); var decade = Math.floor(age / 10) * 10; var decadeLabel = decade + '代'; // Filter by age decade and gender var group = allData.filter(function(d){ var dDecade = Math.floor(d.a / 10) * 10; return d.g === gender && dDecade === decade; }); // If too few matches, use all of same gender if(group.length < 20){ group = allData.filter(function(d){ return d.g === gender; }); decadeLabel = ''; } var userRange = (state.falsetto || state.chest) - state.lowest; var ranges = group.map(function(d){ return (d.f || d.c) - d.l; }); var lows = group.map(function(d){ return d.l; }); var chests = group.map(function(d){ return d.c; }); var falsettos = group.map(function(d){ return d.f; }); return { decadeLabel: decadeLabel, genderLabel: gender === 'male' ? '男性' : '女性', rangePct: getPercentile(ranges, userRange, true), lowPct: getPercentile(lows, state.lowest, false), chestPct: getPercentile(chests, state.chest, true), falsettoPct: getPercentile(falsettos, state.falsetto, true) }; } /* ============================================ モーダル / 報告フロー ============================================ */ function showModal(){ var overlay = document.getElementById('vrc-modal-overlay'); overlay.classList.add('show'); // Reset steps document.getElementById('vrc-step1').style.display = 'block'; document.getElementById('vrc-step2').style.display = 'none'; document.getElementById('vrc-step3').style.display = 'none'; // Show range summary var rangeDiv = document.getElementById('vrc-modal-range'); var rangeWidth = (state.falsetto || state.chest) - state.lowest; rangeDiv.innerHTML = 'あなたの音域' + '' + midiToName(state.lowest) + ' 〜 ' + midiToName(state.chest) + (state.falsetto ? '(裏声 ' + midiToName(state.falsetto) + ')' : '') + '' + '音域の幅:' + rangeWidth + '半音(約' + (Math.round(rangeWidth/12*10)/10) + 'オクターブ)'; } function hideModal(){ document.getElementById('vrc-modal-overlay').classList.remove('show'); } function showStep2(){ document.getElementById('vrc-step1').style.display = 'none'; document.getElementById('vrc-step2').style.display = 'block'; state.gender = null; document.getElementById('vrc-g-male').classList.remove('selected'); document.getElementById('vrc-g-female').classList.remove('selected'); document.getElementById('vrc-age').value = ''; document.getElementById('vrc-submit-btn').disabled = true; } function selectGender(g){ state.gender = g; document.getElementById('vrc-g-male').classList.toggle('selected', g==='male'); document.getElementById('vrc-g-female').classList.toggle('selected', g==='female'); checkSubmitReady(); } function checkSubmitReady(){ var age = parseInt(document.getElementById('vrc-age').value); document.getElementById('vrc-submit-btn').disabled = !(state.gender && age >= 10 && age <= 80); } function submitReport(){ var age = parseInt(document.getElementById('vrc-age').value); if(!state.gender || !age) return; // Save to localStorage (fallback for WP REST API) var report = { g: state.gender, a: age, l: state.lowest, c: state.chest, f: state.falsetto, ts: Date.now() }; USER_DATA.push(report); try { localStorage.setItem('vrc_reports', JSON.stringify(USER_DATA)); } catch(e){} // Try WP REST API if(typeof wp !== 'undefined' && wp.apiFetch){ try { wp.apiFetch({ path: '/vrc/v1/report', method: 'POST', data: report }).catch(function(){}); } catch(e){} } // Show percentile results var stats = calcStats(age, state.gender); showStep3(stats); } function getRangeEvaluation(rangePct){ if(rangePct >= 90) return 'とても広い'; if(rangePct >= 70) return '広い'; if(rangePct >= 50) return 'やや広い'; if(rangePct >= 30) return '標準的'; if(rangePct >= 15) return 'やや狭い'; return '狭め'; } function showStep3(stats){ document.getElementById('vrc-step2').style.display = 'none'; document.getElementById('vrc-step3').style.display = 'block'; var prefix = stats.decadeLabel ? stats.decadeLabel + 'の' : ''; var rangeWidth = (state.falsetto || state.chest) - state.lowest; var rangeEval = getRangeEvaluation(stats.rangePct); var content = document.getElementById('vrc-pct-content'); content.innerHTML = '
' + '' + midiToName(state.lowest) + ' 〜 ' + midiToName(state.chest) + (state.falsetto ? '(裏声 ' + midiToName(state.falsetto) + ')' : '') + '' + '' + rangeWidth + '半音(約' + (Math.round(rangeWidth/12*10)/10) + 'オクターブ)' + '' + rangeEval + '' + '
' + '
' + '' + prefix + stats.genderLabel + 'の' + '' + stats.rangePct + '%' + 'より音域が広いです' + '
' + '
' + '
最低音' + stats.lowPct + '%より低い
' + '
地声最高音' + stats.chestPct + '%より高い
' + '
裏声最高音' + stats.falsettoPct + '%より高い
' + '
'; } /* ============================================ イベントハンドラ ============================================ */ function init(){ buildPiano(); // Mode buttons ['lowest','chest','falsetto'].forEach(function(m){ document.getElementById('vrc-btn-'+m).addEventListener('click', function(e){ e.preventDefault(); if(state.currentNote !== null){ setRangeValue(m, state.currentNote); } }); }); // Diagnose button document.getElementById('vrc-diagnose-btn').addEventListener('click', function(){ diagnose(); }); // Reset button document.getElementById('vrc-reset-btn').addEventListener('click', function(){ resetAll(); }); // Report button document.getElementById('vrc-report-btn').addEventListener('click', function(){ showModal(); }); // Modal CTA document.getElementById('vrc-cta-btn').addEventListener('click', function(){ showStep2(); }); // Gender buttons document.getElementById('vrc-g-male').addEventListener('click', function(){ selectGender('male'); }); document.getElementById('vrc-g-female').addEventListener('click', function(){ selectGender('female'); }); // Age input document.getElementById('vrc-age').addEventListener('input', function(){ checkSubmitReady(); }); // Submit button document.getElementById('vrc-submit-btn').addEventListener('click', function(){ submitReport(); }); // Modal close document.getElementById('vrc-modal-x').addEventListener('click', function(){ hideModal(); }); document.getElementById('vrc-modal-done').addEventListener('click', function(){ hideModal(); }); document.getElementById('vrc-modal-overlay').addEventListener('click', function(e){ if(e.target === this) hideModal(); }); // Search document.getElementById('vrc-search').addEventListener('input', function(){ state.searchQuery = this.value; renderSongTable(); }); // Filters var filterBtns = document.querySelectorAll('.vrc-filter-btn'); filterBtns.forEach(function(btn){ btn.addEventListener('click', function(){ filterBtns.forEach(function(b){ b.classList.remove('active'); }); this.classList.add('active'); state.filter = this.dataset.filter; state.showCount = 5; renderSongTable(); }); }); // Show more document.getElementById('vrc-show-more').addEventListener('click', function(){ state.showCount += 5; renderSongTable(); }); // Song tabs (normal / vocaloid) var tabBtns = document.querySelectorAll('.vrc-tab-btn'); tabBtns.forEach(function(btn){ btn.addEventListener('click', function(){ tabBtns.forEach(function(b){ b.classList.remove('active'); }); this.classList.add('active'); state.songMode = this.dataset.tab; state.showCount = 5; state.filter = 'all'; state.searchQuery = ''; document.getElementById('vrc-search').value = ''; // Update filter buttons filterBtns.forEach(function(b){ b.classList.remove('active'); }); document.querySelector('.vrc-filter-btn[data-filter="all"]').classList.add('active'); // Hide/show suit filters for vocaloid var suitBtns = document.querySelectorAll('.vrc-filter-btn[data-filter="male"],.vrc-filter-btn[data-filter="female"]'); suitBtns.forEach(function(b){ b.style.display = state.songMode === 'vocaloid' ? 'none' : ''; }); // Update ranking link var refLink = document.getElementById('vrc-ranking-ref'); if(refLink){ if(state.songMode === 'vocaloid'){ refLink.href = 'https://www.clubdam.com/genre/vocaloid/ranking_secondhalf.html'; refLink.textContent = 'DAM ボカロランキング'; } else { refLink.href = 'https://www.clubdam.com/ranking/annual2025/'; refLink.textContent = 'DAM 2025年間ランキング'; } } // Re-render if diagnosed if(state.diagnosed){ showPicks(); renderSongTable(); } }); }); // X share buttons function shareOnX(){ var low = state.lowest ? midiToName(state.lowest) : ''; var chest = state.chest ? midiToName(state.chest) : ''; var fal = state.falsetto ? midiToName(state.falsetto) : ''; var rangeWidth = (state.falsetto || state.chest) - state.lowest; var rangePct = Math.round(rangeWidth / 48 * 100); var rangeEval = getRangeEvaluation(rangePct); var rangeText = low + ' 〜 ' + chest + (fal ? '(裏声 ' + fal + ')' : ''); var text = '私の音域は ' + rangeText + ' で「' + rangeEval + '」でした!\n#音域チェッカー'; var url = 'https://label-clach.jp/?p=2717'; var intentUrl = 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(text) + '&url=' + encodeURIComponent(url); window.open(intentUrl, '_blank', 'width=550,height=420'); } var shareBtn = document.getElementById('vrc-share-x'); if(shareBtn) shareBtn.addEventListener('click', shareOnX); var shareBtnModal = document.getElementById('vrc-share-x-modal'); if(shareBtnModal) shareBtnModal.addEventListener('click', shareOnX); // Drag scroll with momentum for picks track var picksTrack = document.getElementById('vrc-picks-track'); if(picksTrack){ var ds = {active:false, startX:0, scrollStart:0, moved:false, lastX:0, lastT:0, velocity:0, raf:0}; picksTrack.addEventListener('dragstart', function(e){ e.preventDefault(); }); picksTrack.addEventListener('mousedown', function(e){ cancelAnimationFrame(ds.raf); ds.active = true; ds.moved = false; ds.startX = e.pageX; ds.lastX = e.pageX; ds.lastT = Date.now(); ds.velocity = 0; ds.scrollStart = picksTrack.scrollLeft; picksTrack.style.cursor = 'grabbing'; picksTrack.style.userSelect = 'none'; }); window.addEventListener('mousemove', function(e){ if(!ds.active) return; var dx = e.pageX - ds.startX; if(Math.abs(dx) > 5) ds.moved = true; e.preventDefault(); var now = Date.now(); var dt = now - ds.lastT; if(dt > 0) ds.velocity = (ds.lastX - e.pageX) / dt; ds.lastX = e.pageX; ds.lastT = now; picksTrack.scrollLeft = ds.scrollStart - dx; }); window.addEventListener('mouseup', function(e){ if(!ds.active) return; ds.active = false; picksTrack.style.cursor = 'grab'; picksTrack.style.removeProperty('user-select'); if(!ds.moved){ var card = e.target.closest('.vrc-pick-card[data-link]'); if(card) window.open(card.dataset.link, '_blank'); } else { var v = ds.velocity * 300; var friction = 0.95; (function coast(){ if(Math.abs(v) < 0.5) return; picksTrack.scrollLeft += v * 0.016; v *= friction; ds.raf = requestAnimationFrame(coast); })(); } }); picksTrack.addEventListener('touchstart', function(e){ cancelAnimationFrame(ds.raf); }, {passive:true}); picksTrack.style.cursor = 'grab'; } } if(document.readyState === 'loading'){ document.addEventListener('DOMContentLoaded', init); } else { init(); } })();