Primeira alteração do código original

This commit is contained in:
Rafael Tavares Juliani committed 2025-05-18 02:18:34 -03:00
1 parent d8efdf827a
commit 458079bbc8
5 files changed
+532 -49

No files matched your search

+193 -48
View File
@@ -1,40 +1,79 @@
<!doctype html>
<html lang="en-us">
<html lang="pt-br">
<head>
<title>ggwave : javascript example</title>
<title>Moan Áudio Link</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="AudioLinkIcon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Goldman:wght@400;700&family=Josefin+Sans:ital,wght@0,100..700;1,100..700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="estilo.css">
</head>
<body>
<div id="main-container">
Minimal <b>ggwave</b> example using Javascript bindings
<h1>
<img src="AudioLinkIcon.svg" alt="Ícone De uma orelha ouvindo um qr code">
Moan Áudio Link
</h1>
<div id="capturaSetor" class="setores">
<br><br>
<img id="listeningIcon" src="ANIMATEDstreamline--ear-hearing-solid.gif" alt="Ouvindo">
<button id="captureStart" class="button-34">Capturar</button>
<button id="captureStop" class="button-34" hidden>Parar</button>
<div>Tx Data:</div> <textarea name="textarea" id="txData" style="width:300px;height:100px;">Hello javascript</textarea><br>
<button onclick="onSend();">Send</button>
<br><br>
<div>Rx data:</div> <textarea name="textarea" id="rxData" style="width:300px;height:100px;" disabled></textarea><br>
<button id="captureStart">Start capturing</button>
<button id="captureStop" hidden>Stop capturing</button>
<br><br>
<div class="cell-version">
<span>
|
Build time: <span class="nav-link">@GIT_DATE@</span> |
Commit hash: <a class="nav-link" href="https://github.com/ggerganov/ggwave/commit/@GIT_SHA1@">@GIT_SHA1@</a> |
Commit subject: <span class="nav-link">@GIT_COMMIT_SUBJECT@</span> |
<a class="nav-link" href="https://github.com/ggerganov/ggwave/tree/master/examples/ggwave-js">Source Code</a> |
</span>
<!-- Radio buttons -->
<div>
<label>
<input type="radio" name="modoCaptura" value="link" checked>
Link automático
</label>
<label style="margin-left: 1em;">
<input type="radio" name="modoCaptura" value="texto">
Somente texto
</label>
</div>
</div>
<div id="redirecionamentoTXT" class="setores">
<div class="spinner"></div>
<p>Redirecionando para <span id="rxData"></span> em <span id="countdown">3</span> segundo(s).</p>
</div>
<div id="divTXT" class="setores">
<p>O código é <span id="rxDataTXT">...</span></p>
</div>
<div id="gerarSetor" class="setores">
<h2>Gerar código sonoro</h2>
<textarea name="textarea" id="txData">https://livro.online</textarea><br>
<div>
<button class="button-34" onclick="onSend();">Gerar</button>
<button class="button-34" onclick="downloadAsMP3()">Download</button>
</div>
</div>
<p>É uma espécie de "qr code" sonoro. Neste app, você pode gerar um código sonoro a partir de um link e, depois neste mesmo app, ouvir esse código e ir automaticamente para o link.</p>
<a class="nav-link" href="https://gitea.livro.online/editoramoan/moan-audio-link">Código fonte</a>
<script type="text/javascript" src="ggwave.js"></script>
<script src="https://unpkg.com/[email protected]/lame.min.js"></script>
<script type='text/javascript'>
function getModoCapturaSelecionado() {
const selecionado = document.querySelector('input[name="modoCaptura"]:checked');
return selecionado ? selecionado.value : null;
}
window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;
@@ -54,8 +93,17 @@
var txData = document.getElementById("txData");
var rxData = document.getElementById("rxData");
var captureStart = document.getElementById("captureStart");
var rxDataTXT = document.getElementById("rxDataTXT");
var listeningIcon = document.getElementById("listeningIcon");
var countdown = document.getElementById("countdown");
var redirecionamentoTXT = document.getElementById("redirecionamentoTXT");
var capturaSetor = document.getElementById("capturaSetor");
var captureStop = document.getElementById("captureStop");
let count = 3; // 3 segundos para o countdown
const countdownEl = document.getElementById("countdown");
const radios = document.querySelectorAll('input[name="modoCaptura"]');
const divTXT = document.getElementById("divTXT");
// helper function
function convertTypedArray(src, type) {
@@ -76,10 +124,31 @@
}
}
//Função para atualizar a visibilidade da divTXT
function atualizarVisibilidadeDivTXT() {
const selecionado = document.querySelector('input[name="modoCaptura"]:checked');
if (selecionado?.value === "texto") {
divTXT.style.display = "FLEX";
} else {
divTXT.style.display = "none";
}
}
// Executa ao mudar os radio buttons
radios.forEach(radio => {
radio.addEventListener("change", atualizarVisibilidadeDivTXT);
});
// Executa uma vez ao carregar a página
document.addEventListener("DOMContentLoaded", atualizarVisibilidadeDivTXT);
//
// Tx
//
let lastAudioBuffer = null; // variável global
function onSend() {
init();
@@ -93,12 +162,60 @@
var buf = convertTypedArray(waveform, Float32Array);
var buffer = context.createBuffer(1, buf.length, context.sampleRate);
buffer.getChannelData(0).set(buf);
// salvar buffer para download posterior
lastAudioBuffer = buffer;
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.start(0);
}
//Dar a opção de download
function downloadAsMP3() {
if (!lastAudioBuffer) {
alert("Nenhum áudio gerado ainda.");
return;
}
const samples = lastAudioBuffer.getChannelData(0);
const mp3encoder = new lamejs.Mp3Encoder(1, lastAudioBuffer.sampleRate, 128); // mono, sampleRate, 128kbps
const blockSize = 1152;
let mp3Data = [];
for (let i = 0; i < samples.length; i += blockSize) {
const sampleChunk = samples.subarray(i, i + blockSize);
const int16Chunk = floatTo16BitPCM(sampleChunk);
const mp3buf = mp3encoder.encodeBuffer(int16Chunk);
if (mp3buf.length > 0) mp3Data.push(mp3buf);
}
const mp3buf = mp3encoder.flush();
if (mp3buf.length > 0) mp3Data.push(mp3buf);
const blob = new Blob(mp3Data, { type: 'audio/mp3' });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "moan-audio-link.mp3";
a.click();
URL.revokeObjectURL(url);
}
// utilitário para converter float [-1, 1] para int16
function floatTo16BitPCM(float32Array) {
const output = new Int16Array(float32Array.length);
for (let i = 0; i < float32Array.length; i++) {
let s = Math.max(-1, Math.min(1, float32Array[i]));
output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
}
return output;
}
//
// Rx
//
@@ -137,28 +254,56 @@
recorder.onaudioprocess = function (e) {
var source = e.inputBuffer;
var res = ggwave.decode(instance, convertTypedArray(new Float32Array(source.getChannelData(0)), Int8Array));
var link;
if (res && res.length > 0) {
res = new TextDecoder("utf-8").decode(res);
rxData.value = res;
if (getModoCapturaSelecionado() == "link") {//Se é link automático
res = new TextDecoder("utf-8").decode(res);
// Remove "http://" ou "https://" do início da string
res = res.replace(/^https?:\/\//, "");
// Adiciona "https://" no início
res = "https://" + res;
// Adiciona tag a
link = "<a src=\"" + res + "\">" + res + "</a>";
// remove o primeiro setor. O setor de captura
capturaSetor.style.display = "none";
// Mostra o redirecionamento
redirecionamentoTXT.style.display = "flex";
// Atribui o valor ao rxData
rxData.innerHTML = link;
//countdown e redirecionamento em 3 segundos
const interval = setInterval(() => {
count--;
countdownEl.textContent = count;
if (count <= 0) {
clearInterval(interval);
window.location.href = res;
}
}, 1000);
// Aguarda 3 segundos e redireciona
setTimeout(() => {
window.location.href = res;
}, 3000);
} else if (getModoCapturaSelecionado() == "texto") { //Se é somente texto
res = new TextDecoder("utf-8").decode(res);
// Mostra o texto
divTXT.style.display = "flex";
rxDataTXT.innerHTML = res;
}
}
// obsolete javascript resampling
// since ggwave v0.2.0 the resampling is built-in ggwave
//var offlineCtx = new OfflineAudioContext(source.numberOfChannels, 48000*source.duration, 48000);
//var offlineSource = offlineCtx.createBufferSource();
//offlineSource.buffer = source;
//offlineSource.connect(offlineCtx.destination);
//offlineSource.start();
//offlineCtx.startRendering();
//offlineCtx.oncomplete = function(e) {
// var resampled = e.renderedBuffer.getChannelData(0);
// var res = ggwave.decode(instance, convertTypedArray(new Float32Array(resampled), Int8Array));
// if (res) {
// rxData.value = res;
// }
//};
}
mediaStream.connect(recorder);
@@ -167,7 +312,7 @@
console.error(e);
});
rxData.value = 'Listening ...';
listeningIcon.style.visibility = "visible";
captureStart.hidden = true;
captureStop.hidden = false;
});
@@ -179,7 +324,7 @@
recorder = null;
}
rxData.value = 'Audio capture is paused! Press the "Start capturing" button to analyze audio from the microphone';
listeningIcon.style.visibility = "hidden";
captureStart.hidden = false;
captureStop.hidden = true;
});