9 files changed
+1943
-596
No files matched your search
@@ -1,593 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>AllTalk TTS Generator</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body,
|
|
||||||
textarea,
|
|
||||||
select,
|
|
||||||
input[type="range"],
|
|
||||||
input[type="number"],
|
|
||||||
button {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 20px;
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-container {
|
|
||||||
max-width: 80%;
|
|
||||||
margin: 50px auto;
|
|
||||||
padding: 20px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, .2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-section {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-start;
|
|
||||||
/* Align items to the start */
|
|
||||||
align-items: center;
|
|
||||||
/* Align items vertically */
|
|
||||||
gap: 20px;
|
|
||||||
/* This creates a consistent gap between all child elements */
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
/* Space from bottom if wrapped */
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
/* Removed flex property to stop forcing them to grow */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure select and input elements do not exceed the width of their parent */
|
|
||||||
select,
|
|
||||||
input[type="range"],
|
|
||||||
input[type="number"] {
|
|
||||||
width: 100%;
|
|
||||||
/* They will fill the width of their .setting container */
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
|
|
||||||
select,
|
|
||||||
input[type="range"],
|
|
||||||
input[type="number"] {
|
|
||||||
width: auto;
|
|
||||||
/* Only auto width for larger screens */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
button {
|
|
||||||
background-color: #4caf50;
|
|
||||||
color: #fff;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background-color: #45a049;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-mode {
|
|
||||||
background-color: #121212;
|
|
||||||
color: #ffffff;
|
|
||||||
/* Text color for dark mode background */
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark-mode .form-container {
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modify the text color for elements within dark mode */
|
|
||||||
.dark-mode label,
|
|
||||||
.dark-mode textarea,
|
|
||||||
.dark-mode select,
|
|
||||||
.dark-mode input[type="range"],
|
|
||||||
.dark-mode input[type="number"],
|
|
||||||
.dark-mode button,
|
|
||||||
.dark-mode .error {
|
|
||||||
color: #ffffff;
|
|
||||||
/* Text color for dark mode elements */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modify text color for input elements, textarea, and dropdowns in dark mode */
|
|
||||||
.dark-mode input,
|
|
||||||
.dark-mode textarea,
|
|
||||||
.dark-mode select {
|
|
||||||
color: #000000;
|
|
||||||
/* Text color for input elements, textarea, and dropdowns in dark mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set background color for textarea in dark mode */
|
|
||||||
.dark-mode textarea {
|
|
||||||
background-color: #C0C0C0;
|
|
||||||
/* Light grey background color for textarea in dark mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set background color for option elements within select in dark mode */
|
|
||||||
.dark-mode select {
|
|
||||||
background-color: #C0C0C0;
|
|
||||||
/* Light grey background color for options in dark mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Additional styles if needed for fixed-width dropdowns */
|
|
||||||
.fixed-size-dropdown {
|
|
||||||
width: 130px;
|
|
||||||
/* Adjust the width as needed */
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner {
|
|
||||||
border: 5px solid #f3f3f3;
|
|
||||||
border-top: 5px solid #3498db;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
color: #ff0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Add space between sliders */
|
|
||||||
.slider-setting {
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Adjust the thumb appearance for a more standard line slider look */
|
|
||||||
input[type="range"]::-webkit-slider-thumb,
|
|
||||||
input[type="range"]::-moz-range-thumb,
|
|
||||||
input[type="range"]::-ms-thumb {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 16px;
|
|
||||||
/* Smaller width for a more standard thumb size */
|
|
||||||
height: 16px;
|
|
||||||
/* Smaller height for a more standard thumb size */
|
|
||||||
border-radius: 50%;
|
|
||||||
/* Keep it rounded, or set to 0 for square */
|
|
||||||
background: #3071a9;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: -7px;
|
|
||||||
/* Adjust if needed to align thumb with the track */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<h1>AllTalk TTS Generator</h1>
|
|
||||||
|
|
||||||
<div class="form-container">
|
|
||||||
<div class="input-section">
|
|
||||||
<label for="text_input">Text Input:</label>
|
|
||||||
<textarea id="text_input" rows="8"></textarea> <!-- Removed cols attribute -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="settings-section">
|
|
||||||
|
|
||||||
<div class="setting voice-setting">
|
|
||||||
<label for="character_voice_gen">Character Voice:</label>
|
|
||||||
<select id="character_voice_gen"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting language-setting">
|
|
||||||
<label for="language">Language:</label>
|
|
||||||
<select id="language" name="language" class="fixed-size-dropdown">
|
|
||||||
<option value="ar">Arabic</option>
|
|
||||||
<option value="zh-cn">Chinese (Simplified)</option>
|
|
||||||
<option value="cs">Czech</option>
|
|
||||||
<option value="nl">Dutch</option>
|
|
||||||
<option value="en" selected>English</option>
|
|
||||||
<option value="fr">French</option>
|
|
||||||
<option value="de">German</option>
|
|
||||||
<option value="hu">Hungarian</option>
|
|
||||||
<option value="it">Italian</option>
|
|
||||||
<option value="ja">Japanese</option>
|
|
||||||
<option value="ko">Korean</option>
|
|
||||||
<option value="pl">Polish</option>
|
|
||||||
<option value="pt">Portuguese</option>
|
|
||||||
<option value="ru">Russian</option>
|
|
||||||
<option value="es">Spanish</option>
|
|
||||||
<option value="tr">Turkish</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="setting play-mode-setting">
|
|
||||||
<label for="playMode">Playback:</label>
|
|
||||||
<select id="playMode" name="playMode" class="fixed-size-dropdown">
|
|
||||||
<option value="local" selected>In Browser</option>
|
|
||||||
<option value="remote">On Server</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting theme-mode-setting">
|
|
||||||
<label for="themeMode">Theme:</label>
|
|
||||||
<select id="themeMode" name="themeMode" class="fixed-size-dropdown">
|
|
||||||
<option value="light" selected>Light</option>
|
|
||||||
<option value="dark">Dark</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting chunk-size-setting">
|
|
||||||
<label for="chunkSize">Sentence Chunk Size:</label>
|
|
||||||
<input type="range" id="chunkSize" name="chunkSize" class="slider-setting" min="1" max="10" value="4"
|
|
||||||
oninput="updateChunkSizeValue(this.value)">
|
|
||||||
<span id="chunkSizeValue">3</span> <!-- Display the value of the slider -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="setting volume-setting">
|
|
||||||
<label for="volume">Volume:</label>
|
|
||||||
<input type="range" id="volume" name="volume" class="slider-setting" min="0.1" max="1.0" step="0.1"
|
|
||||||
value="0.8" oninput="updateVolumeValue(this.value)">
|
|
||||||
<span id="volumeValue">0.8</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button onclick="generateTTS()">Generate TTS</button>
|
|
||||||
<button onclick="togglePausePlayback()">Pause/Resume Playback</button>
|
|
||||||
<button onclick="stopPlayback()">Stop Playback</button>
|
|
||||||
<button onclick="previewVoice()">Preview Voice</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="progressIndicator" class="progress-overlay" style="display: none;">
|
|
||||||
<div class="spinner"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
async function fetchVoices() {
|
|
||||||
try {
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/voices");
|
|
||||||
const result = await response.json();
|
|
||||||
const characterVoiceSelect = document.getElementById("character_voice_gen");
|
|
||||||
|
|
||||||
result.voices.forEach(voice => {
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.value = voice;
|
|
||||||
option.text = voice;
|
|
||||||
characterVoiceSelect.add(option);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateVolumeValue(value) {
|
|
||||||
document.getElementById("volumeValue").innerText = value;
|
|
||||||
|
|
||||||
// Set the volume for browser playback
|
|
||||||
audioElement.volume = parseFloat(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let stopTTSGeneration = false;
|
|
||||||
let audioQueue = [];
|
|
||||||
let currentlyPlaying = false;
|
|
||||||
const audioElement = new Audio();
|
|
||||||
|
|
||||||
async function generateTTS() {
|
|
||||||
try {
|
|
||||||
// Reset the flag at the start
|
|
||||||
stopTTSGeneration = false;
|
|
||||||
|
|
||||||
const textInput = document.getElementById("text_input").value;
|
|
||||||
const language = document.getElementById("language").value;
|
|
||||||
const characterVoice = document.getElementById("character_voice_gen").value;
|
|
||||||
const volume = parseFloat(document.getElementById("volume").value);
|
|
||||||
const chunkSize = parseInt(document.getElementById("chunkSize").value);
|
|
||||||
// Retrieve the value of the selected option for playMode from the dropdown
|
|
||||||
const playModeValue = document.getElementById("playMode").value;
|
|
||||||
|
|
||||||
// Clean up the textInput
|
|
||||||
let cleanedText = textInput.replace(/ \- | \– /g, ' '); // Replaces " - " and " – " with " "
|
|
||||||
cleanedText = cleanedText.replace(/\.\s'/g, ".'"); // Correctly remove space between a period and a single quote
|
|
||||||
cleanedText = cleanedText.replace(/'/g, ""); // Remove all single quotes
|
|
||||||
|
|
||||||
// Split text into chunks based on the specified number of sentences
|
|
||||||
const sentences = cleanedText.match(/("[^"]+"|[^.!?]+[.!?]+)/g);
|
|
||||||
const chunks = [];
|
|
||||||
for (let i = 0; i < sentences.length; i += chunkSize) {
|
|
||||||
let chunk = sentences.slice(i, i + chunkSize).map(s => s.trim()).join(' ');
|
|
||||||
chunks.push(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use playModeValue for the conditional check
|
|
||||||
if (playModeValue === "remote") {
|
|
||||||
for (const chunk of chunks) {
|
|
||||||
if (stopTTSGeneration) break; // Stop if flag is set
|
|
||||||
await generateAndPlayRemote(chunk, language, characterVoice, volume);
|
|
||||||
}
|
|
||||||
} else if (playModeValue === "local") {
|
|
||||||
generateAndPlayLocal(chunks, 0);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in generateTTS:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function generateAndPlayLocal(chunks, index) {
|
|
||||||
if (index >= chunks.length || stopTTSGeneration) {
|
|
||||||
return; // Stop if no more chunks or flag is set
|
|
||||||
}
|
|
||||||
if (index >= chunks.length) {
|
|
||||||
// No more chunks to process
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const chunk = chunks[index];
|
|
||||||
const data = new URLSearchParams({
|
|
||||||
text_input: chunk.trim(),
|
|
||||||
text_filtering: "standard",
|
|
||||||
character_voice_gen: document.getElementById("character_voice_gen").value,
|
|
||||||
narrator_enabled: "false",
|
|
||||||
narrator_voice_gen: document.getElementById("character_voice_gen").value,
|
|
||||||
text_not_inside: "character",
|
|
||||||
language: document.getElementById("language").value,
|
|
||||||
output_file_name: "myoutputfile",
|
|
||||||
output_file_timestamp: "true",
|
|
||||||
autoplay: "false",
|
|
||||||
autoplay_volume: document.getElementById("volume").value
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/tts-generate", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
},
|
|
||||||
body: data,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (result.output_file_url) {
|
|
||||||
audioQueue.push(result.output_file_url);
|
|
||||||
if (!currentlyPlaying) {
|
|
||||||
playNextLocalChunk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively call the function with the next index
|
|
||||||
generateAndPlayLocal(chunks, index + 1);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in generateAndPlayLocal with chunk index", index, ":", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function generateAndPlayRemote(chunk, language, characterVoice, volume) {
|
|
||||||
try {
|
|
||||||
if (stopTTSGeneration) {
|
|
||||||
console.log("TTS generation stopped.");
|
|
||||||
return; // Early return if stop flag is set
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = new URLSearchParams({
|
|
||||||
text_input: chunk.trim(),
|
|
||||||
text_filtering: "standard",
|
|
||||||
character_voice_gen: characterVoice,
|
|
||||||
narrator_enabled: "false",
|
|
||||||
narrator_voice_gen: characterVoice,
|
|
||||||
text_not_inside: "character",
|
|
||||||
language: language,
|
|
||||||
output_file_name: "myoutputfile",
|
|
||||||
output_file_timestamp: "true",
|
|
||||||
autoplay: "true",
|
|
||||||
autoplay_volume: volume.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/tts-generate", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
},
|
|
||||||
body: data,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`API error: ${result.detail || 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("TTS generation complete for chunk:", chunk);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in generateAndPlayRemote:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function previewVoice() {
|
|
||||||
const characterVoice = document.getElementById("character_voice_gen").value;
|
|
||||||
try {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("voice", characterVoice);
|
|
||||||
|
|
||||||
const response = await fetch("http://127.0.0.1:7851/api/previewvoice/", {
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (result.status === "generate-success") {
|
|
||||||
// Play the preview audio
|
|
||||||
const audioPreview = new Audio(result.output_file_url);
|
|
||||||
audioPreview.play();
|
|
||||||
} else {
|
|
||||||
throw new Error('Preview generation failed');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in previewVoice:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function playNextLocalChunk() {
|
|
||||||
if (audioQueue.length > 0) {
|
|
||||||
currentlyPlaying = true;
|
|
||||||
const audioUrl = audioQueue.shift();
|
|
||||||
audioElement.src = audioUrl;
|
|
||||||
audioElement.play();
|
|
||||||
|
|
||||||
audioElement.onended = () => {
|
|
||||||
currentlyPlaying = false;
|
|
||||||
playNextLocalChunk();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function togglePausePlayback() {
|
|
||||||
if (audioElement.paused) {
|
|
||||||
audioElement.play();
|
|
||||||
} else {
|
|
||||||
audioElement.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleThemeMode() {
|
|
||||||
// Retrieve the value of the selected option for themeMode from the dropdown
|
|
||||||
const themeModeValue = document.getElementById('themeMode').value;
|
|
||||||
|
|
||||||
if (themeModeValue === "dark") {
|
|
||||||
document.body.classList.add('dark-mode');
|
|
||||||
localStorage.setItem('darkMode', 'enabled'); // Assuming saveDarkModePreference sets this
|
|
||||||
} else {
|
|
||||||
document.body.classList.remove('dark-mode');
|
|
||||||
localStorage.setItem('darkMode', 'disabled'); // Assuming saveDarkModePreference sets this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateChunkSizeValue(value) {
|
|
||||||
document.getElementById("chunkSizeValue").innerText = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optionally, save the dark mode preference in localStorage
|
|
||||||
function saveDarkModePreference(isDarkMode) {
|
|
||||||
localStorage.setItem('darkMode', isDarkMode ? 'enabled' : 'disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopPlayback() {
|
|
||||||
// Stop current audio playback
|
|
||||||
audioElement.pause();
|
|
||||||
audioElement.currentTime = 0;
|
|
||||||
|
|
||||||
// Clear the audio queue, reset playback flag, and stop further TTS generation
|
|
||||||
audioQueue = [];
|
|
||||||
currentlyPlaying = false;
|
|
||||||
stopTTSGeneration = true; // Set flag to stop TTS generation
|
|
||||||
}
|
|
||||||
|
|
||||||
function showProgress() {
|
|
||||||
document.getElementById('progressIndicator').style.display = 'flex';
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideProgress() {
|
|
||||||
document.getElementById('progressIndicator').style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayOutput(result) {
|
|
||||||
const outputContainer = document.getElementById("output");
|
|
||||||
outputContainer.innerHTML = `<p>Status: ${result.status}</p>`;
|
|
||||||
if (result.output_file_path) {
|
|
||||||
outputContainer.innerHTML += `<p>File Path: ${result.output_file_path}</p>`;
|
|
||||||
}
|
|
||||||
if (result.output_file_url) {
|
|
||||||
outputContainer.innerHTML += `<p>File URL: ${result.output_file_url}</p>`;
|
|
||||||
}
|
|
||||||
if (result.error) {
|
|
||||||
outputContainer.innerHTML += `<p class="error">Error: ${result.error}</p>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
fetchVoices();
|
|
||||||
|
|
||||||
const isDarkModeEnabled = localStorage.getItem('darkMode') === 'enabled';
|
|
||||||
const themeModeSelect = document.getElementById('themeMode');
|
|
||||||
if (isDarkModeEnabled) {
|
|
||||||
document.body.classList.add('dark-mode');
|
|
||||||
themeModeSelect.value = 'dark';
|
|
||||||
} else {
|
|
||||||
themeModeSelect.value = 'light';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add change event listener to the themeMode dropdown
|
|
||||||
themeModeSelect.addEventListener('change', toggleThemeMode);
|
|
||||||
|
|
||||||
// Initialize other elements if necessary
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
+88
-3
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<link rel="shortcut icon" href="#">
|
<link rel="icon" href="./static/favicon.ico" type="image/x-icon">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>AllTalk TTS for Text generation webUI</title>
|
<title>AllTalk TTS for Text generation webUI</title>
|
||||||
@@ -218,6 +218,7 @@
|
|||||||
<li><a href="#getting-started">Getting Started</a></li>
|
<li><a href="#getting-started">Getting Started</a></li>
|
||||||
<li><a href="#server-information">Server Information</a></li>
|
<li><a href="#server-information">Server Information</a></li>
|
||||||
<li><a href="#demotesttts">Demo/Test TTS output</a></li>
|
<li><a href="#demotesttts">Demo/Test TTS output</a></li>
|
||||||
|
<li><a href="#tts-generator">AllTalk TTS Generator</a></li>
|
||||||
<li><a href="#using-voice-samples">Using Voice Samples</a></li>
|
<li><a href="#using-voice-samples">Using Voice Samples</a></li>
|
||||||
<li><a href="#text-not-inside">Text Not inside</a></li>
|
<li><a href="#text-not-inside">Text Not inside</a></li>
|
||||||
<li><a href="#low-vram">Low VRAM</a></li>
|
<li><a href="#low-vram">Low VRAM</a></li>
|
||||||
@@ -271,6 +272,8 @@
|
|||||||
here</a><br />Update instructions <a href="https://github.com/erew123/alltalk_tts?#-updating"
|
here</a><br />Update instructions <a href="https://github.com/erew123/alltalk_tts?#-updating"
|
||||||
target="_blank" rel="noopener">link here</a><br />Help and issues <a
|
target="_blank" rel="noopener">link here</a><br />Help and issues <a
|
||||||
href="https://github.com/erew123/alltalk_tts?#-help-with-problems" target="_blank" rel="noopener">link
|
href="https://github.com/erew123/alltalk_tts?#-help-with-problems" target="_blank" rel="noopener">link
|
||||||
|
here</a><br />TTS Generator <a
|
||||||
|
href="http://127.0.0.1:7851/static/tts_chunk_player/tts_chunk_player.html" target="_blank" rel="noopener">link
|
||||||
here<br /><br /></a><span style="text-decoration: underline;"><strong>Text generation webUI</strong></span>
|
here<br /><br /></a><span style="text-decoration: underline;"><strong>Text generation webUI</strong></span>
|
||||||
<br />Web interface <a href="http://{{ params.ip_address }}:7860" target="_blank" rel="noopener">link
|
<br />Web interface <a href="http://{{ params.ip_address }}:7860" target="_blank" rel="noopener">link
|
||||||
here</a> <br />Documentation <a href="https://github.com/oobabooga/text-generation-webui/wiki"
|
here</a> <br />Documentation <a href="https://github.com/oobabooga/text-generation-webui/wiki"
|
||||||
@@ -288,6 +291,7 @@
|
|||||||
<p style="padding-left: 30px;"><a href="#toc">Back to top of page</a></p>
|
<p style="padding-left: 30px;"><a href="#toc">Back to top of page</a></p>
|
||||||
|
|
||||||
<h2 id="demotesttts">Demo/Test TTS</h2>
|
<h2 id="demotesttts">Demo/Test TTS</h2>
|
||||||
|
<p style="padding-left: 30px;">If you are wanting to generate bulk quantites of TTS and have control over them, please see the <a href="#tts-generator">AllTalk TTS Generator</a> below.</p>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<form method="post" action="/tts-demo-request" id="ttsForm">
|
<form method="post" action="/tts-demo-request" id="ttsForm">
|
||||||
<label for="text">Text:</label>
|
<label for="text">Text:</label>
|
||||||
@@ -416,7 +420,7 @@
|
|||||||
let cleanedText = textInput.replace(/ \- | \– /g, ' '); // Replace hyphens
|
let cleanedText = textInput.replace(/ \- | \– /g, ' '); // Replace hyphens
|
||||||
cleanedText = cleanedText.replace(/%/g, " percent");
|
cleanedText = cleanedText.replace(/%/g, " percent");
|
||||||
//cleanedText = cleanedText.replace(/([!?.])\1+/g, '$1');
|
//cleanedText = cleanedText.replace(/([!?.])\1+/g, '$1');
|
||||||
cleanedText = cleanedText.replace(/[^a-zA-Z0-9\s\.,;:!?\-\'"À-ÿ\u0400-\u04FF\u0150\u0151\u0170\u0171]/g, '');
|
cleanedText = cleanedText.replace(/[^a-zA-Z0-9\s\.,;:!?\-\'"À-ÿ\u0400-\u04FF]/g, '');
|
||||||
cleanedText = cleanedText.replace(/\n+/g, ' ');
|
cleanedText = cleanedText.replace(/\n+/g, ' ');
|
||||||
cleanedText = cleanedText.replace(/\.\s'/g, ".'"); // Remove space between period and single quote
|
cleanedText = cleanedText.replace(/\.\s'/g, ".'"); // Remove space between period and single quote
|
||||||
//cleanedText = cleanedText.replace(/'/g, ""); // Remove all single quotes
|
//cleanedText = cleanedText.replace(/'/g, ""); // Remove all single quotes
|
||||||
@@ -452,6 +456,87 @@
|
|||||||
</script>
|
</script>
|
||||||
<p style="padding-left: 30px;"><a href="#toc">Back to top of page</a></p>
|
<p style="padding-left: 30px;"><a href="#toc">Back to top of page</a></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="tts-generator"><strong>AllTalk TTS Generator</strong></h2>
|
||||||
|
<p style="padding-left: 30px;">AllTalk TTS Generator is the solution for converting large volumes of text into
|
||||||
|
speech using the voice of your choice. Whether you're creating audio content or just want to hear text read
|
||||||
|
aloud, the TTS Generator is equipped to handle it all efficiently.</p>
|
||||||
|
<p style="padding-left: 30px;">The TTS Generator is available on this <a
|
||||||
|
href="http://127.0.0.1:7851/static/tts_chunk_player/tts_chunk_player.html" target="_blank"
|
||||||
|
rel="noopener">link</a></p>
|
||||||
|
<h4>Quick Start</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Text Input:</strong> Enter the text you wish to convert into speech in the 'Text Input' box.</li>
|
||||||
|
<li><strong>Generate TTS Button:</strong> Hit this to start the text-to-speech conversion.</li>
|
||||||
|
<li><strong>Pause/Resume:</strong> Used to pause and resume the playback of the initial generation of wavs or
|
||||||
|
the stream.</li>
|
||||||
|
<li><strong>Stop Playback:</strong> This will stop the current audio playing back. It does not stop the text
|
||||||
|
from being generated however.</li>
|
||||||
|
</ul>
|
||||||
|
<p style="padding-left: 30px;">Once you have sent text off to be generated, either as a stream or wav file
|
||||||
|
generation, the TTS server will remain busy until this process has competed. As such, think carefully as to how
|
||||||
|
much you want to send to the server.</p>
|
||||||
|
<p style="padding-left: 30px;">If you are generating wav files and populating the queue, you can generate one lot of
|
||||||
|
text to speech, then input your next lot of text and it will continue adding to the list.</p>
|
||||||
|
<h4>TTS Generation Modes</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Wav Chunks:</strong> Perfect for creating audio books, or anything you want to keep long term.
|
||||||
|
Breaks down your text into manageable wav files and queues them up. Generation begins automatically, and
|
||||||
|
playback will start after a few chunks have been prepared ahead. You can set the volume to 0 if you
|
||||||
|
don’t want to hear playback. With Wav chunks, you can edit and/or regenerate portions of the TTS as
|
||||||
|
needed.</li>
|
||||||
|
<li><strong>Streaming:</strong> For immediate playback without the ability to save. Ideal for on-the-fly speech
|
||||||
|
generation and listening. This will not generate wav files and it will play back through your browser. You
|
||||||
|
cannot stop the server generating the TTS once it has been sent.</li>
|
||||||
|
</ul>
|
||||||
|
<p style="padding-left: 30px;">With wav chunks you can either playback “In Browser” which is the web
|
||||||
|
page you are on, or “On Server” which is through the console/terminal where AllTalk is running from.
|
||||||
|
Only generation “In Browser” can play back smoothly and populate the Generated TTS List. Setting the
|
||||||
|
Volume will affect the volume level played back both “In Browser” and “On Server”.</p>
|
||||||
|
<h4>Playback and List Management</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Playback Controls:</strong> Utilize 'Play List' to start from the beginning or 'Stop Playback' to
|
||||||
|
halt at any time.</li>
|
||||||
|
<li><strong>Custom Start:</strong> Jump into your list at a specific ID to hear a particular section.</li>
|
||||||
|
<li><strong>Regeneration and Editing:</strong> If a chunk isn't quite right, you can opt to regenerate it or
|
||||||
|
edit the text directly. Click off the text to save changes and hit regenerate for the specific line.</li>
|
||||||
|
<li><strong>Export/Import List:</strong> Save your TTS list as a JSON file or import one. Note: Existing wav
|
||||||
|
files are needed for playback. Exporting is handy if you want to take your files away into another program
|
||||||
|
and have a list of which wav is which, or if you keep your audio files, but want to come back at a later
|
||||||
|
date, edit one or two lines, regenerate the speech and re-combine the wav’s into one new long wav.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h4>Exporting Your Audio</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Export to WAV:</strong> Combine all generated TTS from the list, into one single WAV file for easy
|
||||||
|
download and distribution.</li>
|
||||||
|
</ul>
|
||||||
|
<h4>Customization and Preferences</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Character Voice:</strong> Choose the voice that will read your text.</li>
|
||||||
|
<li><strong>Language:</strong> Select the language of your text.</li>
|
||||||
|
<li><strong>Chunk Sizes:</strong> Decide the size of text chunks for generation. Smaller sizes are recommended
|
||||||
|
for better TTS quality.</li>
|
||||||
|
</ul>
|
||||||
|
<h4>Interface and Accessibility</h4>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Dark/Light Mode:</strong> Switch between themes for your visual comfort.</li>
|
||||||
|
<li><strong>Word Count and Generation Queue:</strong> Keep track of the word count and the generation progress.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h4>Notes on Usage</h4>
|
||||||
|
<ul>
|
||||||
|
<li>For seamless TTS generation, it's advised to keep text chunks under 250 characters, which you can control
|
||||||
|
with the Chunk sizes.</li>
|
||||||
|
<li>Generated audio can be played back from the list, which also highlights the currently playing chunk.</li>
|
||||||
|
<li>The TTS Generator remembers your settings, so you can pick up where you left off even after refreshing the
|
||||||
|
page.</li>
|
||||||
|
</ul>
|
||||||
|
<p style="padding-left: 30px;"><a href="#toc">Back to top of page</a></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h2 id="using-voice-samples"><strong>Using Voice Samples</strong></h2>
|
<h2 id="using-voice-samples"><strong>Using Voice Samples</strong></h2>
|
||||||
<h4 id="where-are-the-sample-voices-stored">Where are the sample voices stored?</h4>
|
<h4 id="where-are-the-sample-voices-stored">Where are the sample voices stored?</h4>
|
||||||
<p style="padding-left: 30px;">Voice samples are stored in <span style="color: #3366ff;">/alltalk_tts/voices/</span>
|
<p style="padding-left: 30px;">Voice samples are stored in <span style="color: #3366ff;">/alltalk_tts/voices/</span>
|
||||||
@@ -1431,4 +1516,4 @@
|
|||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
+179
@@ -0,0 +1,179 @@
|
|||||||
|
export interface CrunkerConstructorOptions {
|
||||||
|
/**
|
||||||
|
* Sample rate for Crunker's internal audio context.
|
||||||
|
*
|
||||||
|
* @default 44100
|
||||||
|
*/
|
||||||
|
sampleRate: number;
|
||||||
|
}
|
||||||
|
export type CrunkerInputTypes = string | File | Blob;
|
||||||
|
/**
|
||||||
|
* An exported Crunker audio object.
|
||||||
|
*/
|
||||||
|
export interface ExportedCrunkerAudio {
|
||||||
|
blob: Blob;
|
||||||
|
url: string;
|
||||||
|
element: HTMLAudioElement;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Crunker is the simple way to merge, concatenate, play, export and download audio files using the Web Audio API.
|
||||||
|
*/
|
||||||
|
export default class Crunker {
|
||||||
|
private readonly _sampleRate;
|
||||||
|
private readonly _context;
|
||||||
|
/**
|
||||||
|
* Creates a new instance of Crunker with the provided options.
|
||||||
|
*
|
||||||
|
* If `sampleRate` is not defined, it will auto-select an appropriate sample rate
|
||||||
|
* for the device being used.
|
||||||
|
*/
|
||||||
|
constructor({ sampleRate }?: Partial<CrunkerConstructorOptions>);
|
||||||
|
/**
|
||||||
|
* Creates Crunker's internal AudioContext.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _createContext;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The internal AudioContext used by Crunker.
|
||||||
|
*/
|
||||||
|
get context(): AudioContext;
|
||||||
|
/**
|
||||||
|
* Asynchronously fetches multiple audio files and returns an array of AudioBuffers.
|
||||||
|
*/
|
||||||
|
fetchAudio(...filepaths: CrunkerInputTypes[]): Promise<AudioBuffer[]>;
|
||||||
|
/**
|
||||||
|
* Merges (layers) multiple AudioBuffers into a single AudioBuffer.
|
||||||
|
*
|
||||||
|
* **Visual representation:**
|
||||||
|
*
|
||||||
|
* 
|
||||||
|
*/
|
||||||
|
mergeAudio(buffers: AudioBuffer[]): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Concatenates multiple AudioBuffers into a single AudioBuffer.
|
||||||
|
*
|
||||||
|
* **Visual representation:**
|
||||||
|
*
|
||||||
|
* 
|
||||||
|
*/
|
||||||
|
concatAudio(buffers: AudioBuffer[]): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Pads a specified AudioBuffer with silence from a specified start time,
|
||||||
|
* for a specified length of time.
|
||||||
|
*
|
||||||
|
* Accepts float values as well as whole integers.
|
||||||
|
*
|
||||||
|
* @param buffer AudioBuffer to pad
|
||||||
|
* @param padStart Time to start padding (in seconds)
|
||||||
|
* @param seconds Duration to pad for (in seconds)
|
||||||
|
*/
|
||||||
|
padAudio(buffer: AudioBuffer, padStart?: number, seconds?: number): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Slices an AudioBuffer from the specified start time to the end time, with optional fade in and out.
|
||||||
|
*
|
||||||
|
* @param buffer AudioBuffer to slice
|
||||||
|
* @param start Start time (in seconds)
|
||||||
|
* @param end End time (in seconds)
|
||||||
|
* @param fadeIn Fade in duration (in seconds, default is 0)
|
||||||
|
* @param fadeOut Fade out duration (in seconds, default is 0)
|
||||||
|
*/
|
||||||
|
sliceAudio(buffer: AudioBuffer, start: number, end: number, fadeIn?: number, fadeOut?: number): AudioBuffer;
|
||||||
|
/**
|
||||||
|
* Plays the provided AudioBuffer in an AudioBufferSourceNode.
|
||||||
|
*/
|
||||||
|
play(buffer: AudioBuffer): AudioBufferSourceNode;
|
||||||
|
/**
|
||||||
|
* Exports the specified AudioBuffer to a Blob, Object URI and HTMLAudioElement.
|
||||||
|
*
|
||||||
|
* Note that changing the MIME type does not change the actual file format. The
|
||||||
|
* file format will **always** be a WAVE file due to how audio is stored in the
|
||||||
|
* browser.
|
||||||
|
*
|
||||||
|
* @param buffer Buffer to export
|
||||||
|
* @param type MIME type (default: `audio/wav`)
|
||||||
|
*/
|
||||||
|
export(buffer: AudioBuffer, type?: string): ExportedCrunkerAudio;
|
||||||
|
/**
|
||||||
|
* Downloads the provided Blob.
|
||||||
|
*
|
||||||
|
* @param blob Blob to download
|
||||||
|
* @param filename An optional file name to use for the download (default: `crunker`)
|
||||||
|
*/
|
||||||
|
download(blob: Blob, filename?: string): HTMLAnchorElement;
|
||||||
|
/**
|
||||||
|
* Executes a callback if the browser does not support the Web Audio API.
|
||||||
|
*
|
||||||
|
* Returns the result of the callback, or `undefined` if the Web Audio API is supported.
|
||||||
|
*
|
||||||
|
* @param callback callback to run if the browser does not support the Web Audio API
|
||||||
|
*/
|
||||||
|
notSupported<T>(callback: () => T): T | undefined;
|
||||||
|
/**
|
||||||
|
* Closes Crunker's internal AudioContext.
|
||||||
|
*/
|
||||||
|
close(): this;
|
||||||
|
/**
|
||||||
|
* Returns the largest duration of the longest AudioBuffer.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _maxDuration;
|
||||||
|
/**
|
||||||
|
* Returns the largest number of channels in an array of AudioBuffers.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _maxNumberOfChannels;
|
||||||
|
/**
|
||||||
|
* Returns the sum of the lengths of an array of AudioBuffers.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _totalLength;
|
||||||
|
/**
|
||||||
|
* Returns whether the browser supports the Web Audio API.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _isSupported;
|
||||||
|
/**
|
||||||
|
* Writes the WAV headers for the specified Float32Array.
|
||||||
|
*
|
||||||
|
* Returns a DataView containing the WAV headers and file content.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _writeHeaders;
|
||||||
|
/**
|
||||||
|
* Converts a Float32Array to 16-bit PCM.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _floatTo16BitPCM;
|
||||||
|
/**
|
||||||
|
* Writes a string to a DataView at the specified offset.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _writeString;
|
||||||
|
/**
|
||||||
|
* Converts an AudioBuffer to a Float32Array.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _interleave;
|
||||||
|
/**
|
||||||
|
* Creates an HTMLAudioElement whose source is the specified Blob.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _renderAudioElement;
|
||||||
|
/**
|
||||||
|
* Creates an Object URL for the specified Blob.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private _renderURL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
var e={d:(t,n)=>{for(var r in n)e.o(n,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:n[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};function n(e){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(e)}function r(e){return function(e){if(Array.isArray(e))return a(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return a(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return a(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function a(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,(o=a.key,i=void 0,i=function(e,t){if("object"!==n(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var a=r.call(e,t||"default");if("object"!==n(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(o,"string"),"symbol"===n(i)?i:String(i)),a)}var o,i}e.d(t,{Z:()=>u});var u=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.sampleRate;o(this,e),this._context=this._createContext(n),n||(n=this._context.sampleRate),this._sampleRate=n}var t,n,a;return t=e,n=[{key:"_createContext",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:44100;return window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext,new AudioContext({sampleRate:e})}},{key:"context",get:function(){return this._context}},{key:"fetchAudio",value:async function(){for(var e=this,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return await Promise.all(n.map((async function(t){var n;return n=t instanceof File||t instanceof Blob?await t.arrayBuffer():await fetch(t).then((function(e){return e.headers.has("Content-Type")&&!e.headers.get("Content-Type").includes("audio/")&&console.warn("Crunker: Attempted to fetch an audio file, but its MIME type is `".concat(e.headers.get("Content-Type").split(";")[0],"`. We'll try and continue anyway. (file: \"").concat(t,'")')),e.arrayBuffer()})),await e._context.decodeAudioData(n)})))}},{key:"mergeAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._sampleRate*this._maxDuration(e),this._sampleRate);return e.forEach((function(e){for(var n=0;n<e.numberOfChannels;n++){for(var r=t.getChannelData(n),a=e.getChannelData(n),o=e.getChannelData(n).length-1;o>=0;o--)r[o]+=a[o];t.getChannelData(n).set(r)}})),t}},{key:"concatAudio",value:function(e){var t=this._context.createBuffer(this._maxNumberOfChannels(e),this._totalLength(e),this._sampleRate),n=0;return e.forEach((function(e){for(var r=0;r<e.numberOfChannels;r++)t.getChannelData(r).set(e.getChannelData(r),n);n+=e.length})),t}},{key:"padAudio",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(0===n)return e;if(t<0)throw new Error('Crunker: Parameter "padStart" in padAudio must be positive');if(n<0)throw new Error('Crunker: Parameter "seconds" in padAudio must be positive');for(var r=this._context.createBuffer(e.numberOfChannels,Math.ceil(e.length+n*e.sampleRate),e.sampleRate),a=0;a<e.numberOfChannels;a++){var o=e.getChannelData(a);r.getChannelData(a).set(o.subarray(0,Math.ceil(t*e.sampleRate)+1),0),r.getChannelData(a).set(o.subarray(Math.ceil(t*e.sampleRate)+2,r.length+1),Math.ceil((t+n)*e.sampleRate))}return r}},{key:"sliceAudio",value:function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0;if(t>=n)throw new Error('Crunker: "start" time should be less than "end" time in sliceAudio method');for(var o=Math.round((n-t)*this._sampleRate),i=Math.round(t*this._sampleRate),u=this._context.createBuffer(e.numberOfChannels,o,this._sampleRate),l=0;l<e.numberOfChannels;l++)for(var s=e.getChannelData(l),c=u.getChannelData(l),f=0;f<o;f++)c[f]=s[i+f],f<r*this._sampleRate&&(c[f]*=f/(r*this._sampleRate)),f>o-a*this._sampleRate&&(c[f]*=(o-f)/(a*this._sampleRate));return u}},{key:"play",value:function(e){var t=this._context.createBufferSource();return t.buffer=e,t.connect(this._context.destination),t.start(),Line truncated
|
||||||
|
//# sourceMappingURL=crunker.esm.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"crunker.esm.js","mappings":"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 truncated
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
+4
@@ -0,0 +1,4 @@
|
|||||||
|
/*! howler.js v2.2.4 | (c) 2013-2020, James Simpson of GoldFire Studios | MIT License | howlerjs.com */
|
||||||
|
!function(){"use strict";var e=function(){this.init()};e.prototype={init:function(){var e=this||n;return e._counter=1e3,e._html5AudioPool=[],e.html5PoolSize=10,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.autoUnlock=!0,e._setup(),e},volume:function(e){var o=this||n;if(e=parseFloat(e),o.ctx||_(),void 0!==e&&e>=0&&e<=1){if(o._volume=e,o._muted)return o;o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var t=0;t<o._howls.length;t++)if(!o._howls[t]._webAudio)for(var r=o._howls[t]._getSoundIds(),a=0;a<r.length;a++){var u=o._howls[t]._soundById(r[a]);u&&u._node&&(u._node.volume=u._volume*e)}return o}return o._volume},mute:function(e){var o=this||n;o.ctx||_(),o._muted=e,o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e?0:o._volume,n.ctx.currentTime);for(var t=0;t<o._howls.length;t++)if(!o._howls[t]._webAudio)for(var r=o._howls[t]._getSoundIds(),a=0;a<r.length;a++){var u=o._howls[t]._soundById(r[a]);u&&u._node&&(u._node.muted=!!e||u._muted)}return o},stop:function(){for(var e=this||n,o=0;o<e._howls.length;o++)e._howls[o].stop();return e},unload:function(){for(var e=this||n,o=e._howls.length-1;o>=0;o--)e._howls[o].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"suspended":"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var o=new Audio;void 0===o.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var o=new Audio;o.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,o=null;try{o="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!o||"function"!=typeof o.canPlayType)return e;var t=o.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator?e._navigator.userAgent:"",a=r.match(/OPR\/(\d+)/g),u=a&&parseInt(a[0].split("/")[1],10)<33,d=-1!==r.indexOf("Safari")&&-1===r.indexOf("Chrome"),i=r.match(/Version\/(.*?) /),_=d&&i&&parseInt(i[1],10)<15;return e._codecs={mp3:!(u||!t&&!o.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!t,opus:!!o.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!(o.canPlayType('audio/wav; codecs="1"')||o.canPlayType("audio/wav")).replace(/^no$/,""),aac:!!o.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!o.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(o.canPlayType("audio/x-m4a;")||o.canPlayType("audio/m4a;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),m4b:!!(o.canPlayType("audio/x-m4b;")||o.canPlayType("audio/m4b;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(o.canPlayType("audio/x-mp4;")||o.canPlayType("audio/mp4;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),webm:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),dolby:!!o.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(o.canPlayType("audio/x-flac;")||o.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||n;if(!e._audioUnlocked&&e.ctx){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var o=function(n){for(;e._html5AudioPool.length<e.html5PoolSize;)try{var t=new Audio;t._unlocked=!0,e._releaseHtml5Audio(t)}catch(n){e.noAudio=!0;break}for(var r=0;r<e._howls.length;r++)if(!e._howls[r]._webAudio)for(var a=e._howls[r]._getSoundIds(),u=0;u<a.length;u++){var d=e._howls[r]._soundById(a[u]);d&&d._node&&!d._node._unlocked&&(d._node._unlocked=!0,d._node.load())}e._autoResume();var i=e.ctx.createBufferSource();i.buffer=e._scratchBuffer,i.connect(e.ctx.destination),void 0===i.start?i.noteOn(0):i.start(0),"function"==typeof e.ctx.resume&&e.ctx.resume(),i.onended=function(){i.disconnect(0),e._audioUnlocked=!0,document.removeEventListener("touchstart",o,!0),document.removeEventListener("touchend",o,!0),document.removeEventListener("click",o,!0),document.removeEventListener("keydown",o,!0);for(var n=0;n<e._howls.length;n++)e._howls[n]._emit("unlock")}};return document.addEventListener("touchstart",o,!0),document.addEventListener("touchend",o,!0),document.addEventListener("click",o,!0),document.addEventListener("keydown",o,!0),e}},_obtainHtml5Audio:function(){var e=this||n;if(e._html5AudioPool.length)return e._html5AudioPool.pop();var o=(new Audio).play();return o&&"undefined"!=typeof Promise&&(o instanceof Promise||"function"==typeof o.then)&&o.catch(function(){console.warn("HTML5 Audio pool eLine truncated
|
||||||
|
/*! Spatial Plugin */
|
||||||
|
!function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(e){var n=this;if(!n.ctx||!n.ctx.listener)return n;for(var t=n._howls.length-1;t>=0;t--)n._howls[t].stereo(e);return n},HowlerGlobal.prototype.pos=function(e,n,t){var r=this;return r.ctx&&r.ctx.listener?(n="number"!=typeof n?r._pos[1]:n,t="number"!=typeof t?r._pos[2]:t,"number"!=typeof e?r._pos:(r._pos=[e,n,t],void 0!==r.ctx.listener.positionX?(r.ctx.listener.positionX.setTargetAtTime(r._pos[0],Howler.ctx.currentTime,.1),r.ctx.listener.positionY.setTargetAtTime(r._pos[1],Howler.ctx.currentTime,.1),r.ctx.listener.positionZ.setTargetAtTime(r._pos[2],Howler.ctx.currentTime,.1)):r.ctx.listener.setPosition(r._pos[0],r._pos[1],r._pos[2]),r)):r},HowlerGlobal.prototype.orientation=function(e,n,t,r,o,i){var a=this;if(!a.ctx||!a.ctx.listener)return a;var p=a._orientation;return n="number"!=typeof n?p[1]:n,t="number"!=typeof t?p[2]:t,r="number"!=typeof r?p[3]:r,o="number"!=typeof o?p[4]:o,i="number"!=typeof i?p[5]:i,"number"!=typeof e?p:(a._orientation=[e,n,t,r,o,i],void 0!==a.ctx.listener.forwardX?(a.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.forwardY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.forwardZ.setTargetAtTime(t,Howler.ctx.currentTime,.1),a.ctx.listener.upX.setTargetAtTime(r,Howler.ctx.currentTime,.1),a.ctx.listener.upY.setTargetAtTime(o,Howler.ctx.currentTime,.1),a.ctx.listener.upZ.setTargetAtTime(i,Howler.ctx.currentTime,.1)):a.ctx.listener.setOrientation(e,n,t,r,o,i),a)},Howl.prototype.init=function(e){return function(n){var t=this;return t._orientation=n.orientation||[1,0,0],t._stereo=n.stereo||null,t._pos=n.pos||null,t._pannerAttr={coneInnerAngle:void 0!==n.coneInnerAngle?n.coneInnerAngle:360,coneOuterAngle:void 0!==n.coneOuterAngle?n.coneOuterAngle:360,coneOuterGain:void 0!==n.coneOuterGain?n.coneOuterGain:0,distanceModel:void 0!==n.distanceModel?n.distanceModel:"inverse",maxDistance:void 0!==n.maxDistance?n.maxDistance:1e4,panningModel:void 0!==n.panningModel?n.panningModel:"HRTF",refDistance:void 0!==n.refDistance?n.refDistance:1,rolloffFactor:void 0!==n.rolloffFactor?n.rolloffFactor:1},t._onstereo=n.onstereo?[{fn:n.onstereo}]:[],t._onpos=n.onpos?[{fn:n.onpos}]:[],t._onorientation=n.onorientation?[{fn:n.onorientation}]:[],e.call(this,n)}}(Howl.prototype.init),Howl.prototype.stereo=function(n,t){var r=this;if(!r._webAudio)return r;if("loaded"!==r._state)return r._queue.push({event:"stereo",action:function(){r.stereo(n,t)}}),r;var o=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof n)return r._stereo;r._stereo=n,r._pos=[n,0,0]}for(var i=r._getSoundIds(t),a=0;a<i.length;a++){var p=r._soundById(i[a]);if(p){if("number"!=typeof n)return p._stereo;p._stereo=n,p._pos=[n,0,0],p._node&&(p._pannerAttr.panningModel="equalpower",p._panner&&p._panner.pan||e(p,o),"spatial"===o?void 0!==p._panner.positionX?(p._panner.positionX.setValueAtTime(n,Howler.ctx.currentTime),p._panner.positionY.setValueAtTime(0,Howler.ctx.currentTime),p._panner.positionZ.setValueAtTime(0,Howler.ctx.currentTime)):p._panner.setPosition(n,0,0):p._panner.pan.setValueAtTime(n,Howler.ctx.currentTime)),r._emit("stereo",p._id)}}return r},Howl.prototype.pos=function(n,t,r,o){var i=this;if(!i._webAudio)return i;if("loaded"!==i._state)return i._queue.push({event:"pos",action:function(){i.pos(n,t,r,o)}}),i;if(t="number"!=typeof t?0:t,r="number"!=typeof r?-.5:r,void 0===o){if("number"!=typeof n)return i._pos;i._pos=[n,t,r]}for(var a=i._getSoundIds(o),p=0;p<a.length;p++){var s=i._soundById(a[p]);if(s){if("number"!=typeof n)return s._pos;s._pos=[n,t,r],s._node&&(s._panner&&!s._panner.pan||e(s,"spatial"),void 0!==s._panner.positionX?(s._panner.positionX.setValueAtTime(n,Howler.ctx.currentTime),s._panner.positionY.setValueAtTime(t,Howler.ctx.currentTime),s._panner.positionZ.setValueAtTime(r,Howler.ctx.currentTime)):s._panner.setPosition(n,t,r)),i._emit("pos",s._id)}}return i},Howl.prototype.orientation=function(n,t,r,o){var i=this;if(!i._webAudio)return i;if("loaded"!==i._state)return i._queue.push({event:"orientation",action:function(){i.orientation(n,t,r,o)}}),i;if(t="number"!=typeof t?i._orientation[1]:t,r="number"!=typeof r?i._orientation[2]:r,void 0===o){if("number"!=typeof n)return i._orientation;i._orientation=[n,t,r]}for(var a=i._getSoundIds(o),p=0;p<a.length;p++){var s=i._soundById(a[p]);if(s){if("number"!=typeof n)return s._orientation;s._orientation=[n,t,r],s._node&&(s._panner||(s._pos||(s._pos=i._pos||[0,0,-.5]),e(s,"spatial")),void 0!==s._panner.orientationX?(s._panner.orientationX.setValueAtTime(n,Howler.ctx.currentTime),s._panner.orientationY.setValueAtTime(t,Howler.ctx.currentTime),s._panner.orientationZ.setValueAtTime(r,Howler.ctx.currentTime)):s._panner.setOrientation(n,t,r)),i._emit("orientation",s._id)}}return i},Howl.prototype.pannerAttr=function(){var n,t,r,o=this,i=arguments;if(!o._webAudioLine truncated
|
||||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user