soiz1 commited on
Commit
4131348
·
1 Parent(s): cbf9bcd

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +89 -144
index.html CHANGED
@@ -413,12 +413,8 @@
413
  </div>
414
  </div>
415
  </div>
416
- <script type="module">
417
- // SoundTouchJSを正しくインポート
418
- import { SoundTouch, SimpleFilter, PitchShifter } from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/soundtouch.min.js';
419
-
420
- // グローバルにsoundtouchを設定
421
- window.soundtouch = { SoundTouch, SimpleFilter, PitchShifter };
422
  document.addEventListener('DOMContentLoaded', function() {
423
  // 要素を取得
424
  const video = document.getElementById('video');
@@ -444,11 +440,7 @@
444
  const volumeValues = document.querySelectorAll('.volume-value');
445
 
446
  // 音声オブジェクトを作成
447
- const audioContext = new (window.AudioContext || window.webkitAudioContext)();
448
- const audioBuffers = {};
449
- const audioSources = {};
450
- const gainNodes = {};
451
- const soundTouchNodes = {};
452
 
453
  // 音声ファイル名の配列
454
  const audioFiles = ['p', 'a', 't', 's', 'k'];
@@ -468,11 +460,16 @@
468
  startTimeInput.max = videoDuration - 0.1;
469
  updateTimeDisplay();
470
  });
471
- document.getElementById('play-pause-btn').addEventListener('click', function() {
472
- if (audioContext.state === 'suspended') {
473
- audioContext.resume();
474
- }
475
- });
 
 
 
 
 
476
  // 時間表示を更新
477
  function updateTimeDisplay() {
478
  const currentTime = video.currentTime;
@@ -539,11 +536,8 @@
539
 
540
  // 音声も同期
541
  audioFiles.forEach(file => {
542
- if (audioSources[file]) {
543
- audioSources[file].stop();
544
- if (isPlaying) {
545
- playAudio(file, seekTime);
546
- }
547
  }
548
  });
549
  }
@@ -637,15 +631,15 @@
637
  updatePlaybackRate(speed);
638
  });
639
 
640
-
641
  function updatePlaybackRate(speed) {
642
  currentPlaybackRate = speed;
643
  video.playbackRate = speed;
644
 
645
  // 音声の再生速度を変更
646
  audioFiles.forEach(file => {
647
- if (audioSources[file]) {
648
- audioSources[file].processor.tempo = speed;
 
649
  }
650
  });
651
  }
@@ -677,96 +671,65 @@
677
  }
678
  }
679
 
680
- async function loadAudioFiles() {
681
- for (const file of audioFiles) {
682
- try {
683
- const response = await fetch(`${file}.mp3`);
684
- const arrayBuffer = await response.arrayBuffer();
685
- audioBuffers[file] = await audioContext.decodeAudioData(arrayBuffer);
686
- gainNodes[file] = audioContext.createGain();
687
- gainNodes[file].gain.value = 1;
688
- } catch (error) {
689
- console.error(`Error loading ${file}.mp3:`, error);
690
- }
691
- }
 
 
 
 
 
 
 
692
  }
693
 
694
- function playAudio(file, startTime) {
695
- if (!audioBuffers[file]) return;
696
-
697
- // 既存のソースを止める
698
- if (audioSources[file]) {
699
- try {
700
- audioSources[file].stop();
701
- audioSources[file].disconnect();
702
- } catch (e) {}
703
- }
704
-
705
- // 音声ソース
706
- const sourceNode = audioContext.createBufferSource();
707
- sourceNode.buffer = audioBuffers[file];
708
-
709
- // SoundTouch PitchShifterのAudioNodeを作成
710
- const filter = new soundtouch.SimpleFilter(
711
- new soundtouch.SoundTouch(audioBuffers[file].sampleRate),
712
- new soundtouch.BufferSource(audioBuffers[file])
713
- );
714
- filter.tempo = currentPlaybackRate;
715
- filter.pitch = 1.0;
716
-
717
- const filterNode = soundtouch.getWebAudioNode(audioContext, filter);
718
-
719
- // ボリューム
720
- const volumeSlider = document.querySelector(`.audio-slider[data-audio="${file}"]`);
721
- const volume = parseFloat(volumeSlider.value) * parseFloat(globalVolumeSlider.value);
722
- gainNodes[file] = audioContext.createGain();
723
- gainNodes[file].gain.value = volume;
724
-
725
- // 接続
726
- sourceNode.connect(filterNode);
727
- filterNode.connect(gainNodes[file]);
728
- gainNodes[file].connect(audioContext.destination);
729
-
730
- // 再生時間計算
731
- const duration = video.duration || videoDuration;
732
- const endTime = parseFloat(endTimeInput.value) || duration;
733
- const playStartTime = Math.max(startTime, parseFloat(startTimeInput.value) || 0);
734
- const playEndTime = Math.min(endTime, duration);
735
- const playDuration = playEndTime - playStartTime;
736
-
737
- if (playDuration > 0) {
738
- sourceNode.start(audioContext.currentTime, playStartTime);
739
- if (!loopCheckbox.checked) {
740
- setTimeout(() => {
741
- sourceNode.stop();
742
- }, playDuration * 1000);
743
- }
744
- }
745
- audioSources[file] = sourceNode;
746
- }
747
-
748
-
749
-
750
- function pauseMedia() {
751
- if (!isPlaying) return;
752
 
753
- video.pause();
754
- audioFiles.forEach(file => {
755
- if (audioSources[file]) {
756
- try {
757
- audioSources[file].source.stop();
758
- audioSources[file].processor.disconnect();
759
- } catch (e) {
760
- console.log("Audio source already stopped");
761
- }
762
- audioSources[file] = null;
763
- }
764
- });
765
 
766
- isPlaying = false;
767
- isVideoPlaying = false;
768
- playPauseBtn.textContent = '▶';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769
  }
 
770
  // 再生関数
771
  function playMedia() {
772
  const startTime = video.currentTime;
@@ -788,9 +751,7 @@ function playAudio(file, startTime) {
788
 
789
  // 音声を再生
790
  audioFiles.forEach(file => {
791
- if (audioBuffers[file]) {
792
- playAudio(file, video.currentTime);
793
- }
794
  });
795
  }
796
 
@@ -800,13 +761,8 @@ function playAudio(file, startTime) {
800
 
801
  video.pause();
802
  audioFiles.forEach(file => {
803
- if (audioSources[file]) {
804
- try {
805
- audioSources[file].stop();
806
- } catch(e) {
807
- console.log("Audio source already stopped");
808
- }
809
- audioSources[file] = null;
810
  }
811
  });
812
 
@@ -821,9 +777,9 @@ function playAudio(file, startTime) {
821
  const value = parseFloat(this.value);
822
  volumeValues[index].textContent = value.toFixed(2);
823
 
824
- if (isPlaying && gainNodes[this.dataset.audio]) {
825
  const globalVolume = parseFloat(globalVolumeSlider.value);
826
- gainNodes[this.dataset.audio].gain.value = value * globalVolume;
827
  }
828
  });
829
  });
@@ -833,33 +789,22 @@ function playAudio(file, startTime) {
833
  const value = parseFloat(this.value);
834
  globalVolumeValue.textContent = value.toFixed(1);
835
 
836
- if (isPlaying) {
837
- audioFiles.forEach(file => {
838
- if (gainNodes[file]) {
839
- const volumeSlider = document.querySelector(`.audio-slider[data-audio="${file}"]`);
840
- const volume = parseFloat(volumeSlider.value) * value;
841
- gainNodes[file].gain.value = volume;
842
- }
843
- });
844
- }
845
  });
846
 
847
  // ループ設定変更時
848
  loopCheckbox.addEventListener('change', function() {
849
- if (isPlaying) {
850
- // 再生中の場合は音声を再起動
851
- const currentTime = video.currentTime;
852
- audioFiles.forEach(file => {
853
- if (audioSources[file]) {
854
- try {
855
- audioSources[file].stop();
856
- } catch(e) {
857
- console.log("Audio source already stopped");
858
- }
859
- playAudio(file, currentTime);
860
- }
861
- });
862
- }
863
  });
864
 
865
  // 初期化
 
413
  </div>
414
  </div>
415
  </div>
416
+
417
+ <script>
 
 
 
 
418
  document.addEventListener('DOMContentLoaded', function() {
419
  // 要素を取得
420
  const video = document.getElementById('video');
 
440
  const volumeValues = document.querySelectorAll('.volume-value');
441
 
442
  // 音声オブジェクトを作成
443
+ const audioElements = {};
 
 
 
 
444
 
445
  // 音声ファイル名の配列
446
  const audioFiles = ['p', 'a', 't', 's', 'k'];
 
460
  startTimeInput.max = videoDuration - 0.1;
461
  updateTimeDisplay();
462
  });
463
+
464
+ document.getElementById('play-pause-btn').addEventListener('click', function() {
465
+ // 音声要素の再生を許可
466
+ audioFiles.forEach(file => {
467
+ if (audioElements[file]) {
468
+ audioElements[file].play().catch(e => console.log("Audio play failed:", e));
469
+ }
470
+ });
471
+ });
472
+
473
  // 時間表示を更新
474
  function updateTimeDisplay() {
475
  const currentTime = video.currentTime;
 
536
 
537
  // 音声も同期
538
  audioFiles.forEach(file => {
539
+ if (audioElements[file]) {
540
+ audioElements[file].currentTime = seekTime;
 
 
 
541
  }
542
  });
543
  }
 
631
  updatePlaybackRate(speed);
632
  });
633
 
 
634
  function updatePlaybackRate(speed) {
635
  currentPlaybackRate = speed;
636
  video.playbackRate = speed;
637
 
638
  // 音声の再生速度を変更
639
  audioFiles.forEach(file => {
640
+ if (audioElements[file]) {
641
+ audioElements[file].playbackRate = speed;
642
+ audioElements[file].preservesPitch = true; // ピッチを保持
643
  }
644
  });
645
  }
 
671
  }
672
  }
673
 
674
+ // 音声ファイルをロード
675
+ function loadAudioFiles() {
676
+ audioFiles.forEach(file => {
677
+ const audio = new Audio(`${file}.mp3`);
678
+ audio.preload = 'auto';
679
+ audio.preservesPitch = true; // ピッチを保持
680
+ audio.loop = false;
681
+ audioElements[file] = audio;
682
+
683
+ // 音声が読み込まれたら
684
+ audio.addEventListener('loadedmetadata', function() {
685
+ console.log(`${file}.mp3 loaded`);
686
+ });
687
+
688
+ // エラー処理
689
+ audio.addEventListener('error', function() {
690
+ console.error(`Error loading ${file}.mp3`);
691
+ });
692
+ });
693
  }
694
 
695
+ function playAudio(file, startTime) {
696
+ if (!audioElements[file]) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
697
 
698
+ const audio = audioElements[file];
699
+ const duration = video.duration || videoDuration;
700
+ const endTime = parseFloat(endTimeInput.value) || duration;
 
 
 
 
 
 
 
 
 
701
 
702
+ // ボリューム設定
703
+ const volumeSlider = document.querySelector(`.audio-slider[data-audio="${file}"]`);
704
+ const volume = parseFloat(volumeSlider.value) * parseFloat(globalVolumeSlider.value);
705
+ audio.volume = volume;
706
+
707
+ // 再生速度設定
708
+ audio.playbackRate = currentPlaybackRate;
709
+ audio.preservesPitch = true;
710
+
711
+ // 再生時間計算
712
+ const playStartTime = Math.max(startTime, parseFloat(startTimeInput.value) || 0);
713
+ const playEndTime = Math.min(endTime, duration);
714
+
715
+ audio.currentTime = playStartTime;
716
+
717
+ // 再生
718
+ audio.play().catch(e => console.log("Audio play failed:", e));
719
+
720
+ // ループ設定
721
+ audio.loop = loopCheckbox.checked;
722
+
723
+ if (!loopCheckbox.checked) {
724
+ // ループ再生でない場合、終了時間に達したら停止
725
+ setTimeout(() => {
726
+ if (audio.currentTime >= playEndTime) {
727
+ audio.pause();
728
+ }
729
+ }, (playEndTime - playStartTime) * 1000);
730
+ }
731
  }
732
+
733
  // 再生関数
734
  function playMedia() {
735
  const startTime = video.currentTime;
 
751
 
752
  // 音声を再生
753
  audioFiles.forEach(file => {
754
+ playAudio(file, video.currentTime);
 
 
755
  });
756
  }
757
 
 
761
 
762
  video.pause();
763
  audioFiles.forEach(file => {
764
+ if (audioElements[file]) {
765
+ audioElements[file].pause();
 
 
 
 
 
766
  }
767
  });
768
 
 
777
  const value = parseFloat(this.value);
778
  volumeValues[index].textContent = value.toFixed(2);
779
 
780
+ if (audioElements[this.dataset.audio]) {
781
  const globalVolume = parseFloat(globalVolumeSlider.value);
782
+ audioElements[this.dataset.audio].volume = value * globalVolume;
783
  }
784
  });
785
  });
 
789
  const value = parseFloat(this.value);
790
  globalVolumeValue.textContent = value.toFixed(1);
791
 
792
+ audioFiles.forEach(file => {
793
+ if (audioElements[file]) {
794
+ const volumeSlider = document.querySelector(`.audio-slider[data-audio="${file}"]`);
795
+ const volume = parseFloat(volumeSlider.value) * value;
796
+ audioElements[file].volume = volume;
797
+ }
798
+ });
 
 
799
  });
800
 
801
  // ループ設定変更時
802
  loopCheckbox.addEventListener('change', function() {
803
+ audioFiles.forEach(file => {
804
+ if (audioElements[file]) {
805
+ audioElements[file].loop = this.checked;
806
+ }
807
+ });
 
 
 
 
 
 
 
 
 
808
  });
809
 
810
  // 初期化