Update index.html
Browse files- index.html +33 -61
index.html
CHANGED
@@ -697,78 +697,50 @@
|
|
697 |
});
|
698 |
}
|
699 |
|
700 |
-
|
701 |
-
|
702 |
|
703 |
-
|
704 |
-
if (audioSources[file]) {
|
705 |
try {
|
706 |
-
|
707 |
} catch(e) {
|
708 |
-
|
709 |
}
|
710 |
-
|
711 |
-
|
712 |
-
const source = audioContext.createBufferSource();
|
713 |
-
source.buffer = audioBuffers[file];
|
714 |
-
|
715 |
-
// SoundTouch プロセッサーを作成
|
716 |
-
const soundTouch = new SoundTouch(audioBuffers[file].sampleRate);
|
717 |
-
soundTouch.tempo = currentPlaybackRate;
|
718 |
-
soundTouch.pitch = 1;
|
719 |
-
|
720 |
-
// BufferSourceを作成
|
721 |
-
const bufferSource = new soundtouch.WebAudioBufferSource(audioBuffers[file].getChannelData(0));
|
722 |
-
|
723 |
-
// SimpleFilterを作成
|
724 |
-
const filter = new SimpleFilter(soundTouch, bufferSource);
|
725 |
-
|
726 |
-
// ScriptProcessorNodeを作成
|
727 |
-
const processor = audioContext.createScriptProcessor(4096, 1, 1);
|
728 |
-
processor.onaudioprocess = (event) => {
|
729 |
-
const outputBuffer = event.outputBuffer.getChannelData(0);
|
730 |
-
const framesExtracted = filter.extract(outputBuffer, outputBuffer.length);
|
731 |
-
if (framesExtracted === 0) {
|
732 |
-
processor.disconnect();
|
733 |
-
}
|
734 |
-
};
|
735 |
-
|
736 |
-
// ボリュームコントロール
|
737 |
-
const volumeSlider = document.querySelector(`.audio-slider[data-audio="${file}"]`);
|
738 |
-
const volume = parseFloat(volumeSlider.value) * parseFloat(globalVolumeSlider.value);
|
739 |
-
gainNodes[file].gain.value = volume;
|
740 |
|
741 |
-
|
742 |
-
|
743 |
-
processor.connect(gainNodes[file]);
|
744 |
-
gainNodes[file].connect(audioContext.destination);
|
745 |
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
|
|
|
|
752 |
|
753 |
-
|
754 |
-
|
755 |
-
|
|
|
|
|
|
|
756 |
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
|
764 |
-
|
765 |
-
|
766 |
-
processor: processor,
|
767 |
-
filter: filter
|
768 |
-
};
|
769 |
-
soundTouchNodes[file] = soundTouch;
|
770 |
}
|
771 |
|
|
|
|
|
|
|
772 |
// 一時停止関数も修正
|
773 |
function pauseMedia() {
|
774 |
if (!isPlaying) return;
|
|
|
697 |
});
|
698 |
}
|
699 |
|
700 |
+
function playAudio(file, startTime) {
|
701 |
+
if (!audioBuffers[file]) return;
|
702 |
|
703 |
+
if (audioSources[file]) {
|
|
|
704 |
try {
|
705 |
+
audioSources[file].stop();
|
706 |
} catch(e) {
|
707 |
+
console.log("Audio source already stopped");
|
708 |
}
|
709 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
710 |
|
711 |
+
const source = audioContext.createBufferSource();
|
712 |
+
source.buffer = audioBuffers[file];
|
|
|
|
|
713 |
|
714 |
+
// PitchShifter を使用
|
715 |
+
const pitchShifter = new window.soundtouch.PitchShifter(
|
716 |
+
audioContext,
|
717 |
+
audioBuffers[file],
|
718 |
+
4096
|
719 |
+
);
|
720 |
+
pitchShifter.tempo = currentPlaybackRate;
|
721 |
+
pitchShifter.pitch = 1.0;
|
722 |
|
723 |
+
// ボリュームコントロール
|
724 |
+
const volumeSlider = document.querySelector(`.audio-slider[data-audio="${file}"]`);
|
725 |
+
const volume = parseFloat(volumeSlider.value) * parseFloat(globalVolumeSlider.value);
|
726 |
+
pitchShifter.connect(gainNodes[file]);
|
727 |
+
gainNodes[file].gain.value = volume;
|
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 |
+
pitchShifter.start(startTime);
|
|
|
|
|
|
|
|
|
739 |
}
|
740 |
|
741 |
+
audioSources[file] = pitchShifter;
|
742 |
+
}
|
743 |
+
|
744 |
// 一時停止関数も修正
|
745 |
function pauseMedia() {
|
746 |
if (!isPlaying) return;
|