Subject: Real-time Microphone Audio Visualization Similar to FM Synth Example in WaveSurfer.js #3635
Unanswered
JoseRFJuniorLLMs
asked this question in
Q&A
Replies: 1 comment
-
The Record plugin should be a good start: https://wavesurfer.xyz/examples/?record.js |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Dear WaveSurfer.js Team,
I recently came across the FM Synth example on your website (https://wavesurfer.xyz/examples/?fm-synth.js) and was impressed by the real-time waveform visualization. I am working on a project where I need to capture audio from the microphone in real-time and display the waveform in a similar manner. I've been exploring your documentation and examples, but I am facing some challenges in achieving this with the microphone input.
Could you provide guidance or examples on how to integrate real-time microphone audio capture with waveform visualization in WaveSurfer.js? Specifically, I am looking to replicate the seamless real-time visualization seen in the FM Synth example but with audio input from the microphone.
Here's a brief overview of what I've tried so far:
`
import { CommonModule } from '@angular/common';
import { HttpClient, HttpClientModule, HttpHeaders } from '@angular/common/http';
import { Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatRippleModule } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatStepper, MatStepperModule } from '@angular/material/stepper';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { HighlightModule } from 'ngx-highlightjs';
import { QuillEditorComponent } from 'ngx-quill';
import nlp from 'compromise';
import WaveSurfer from 'wavesurfer.js';
import gpt4 from '../../../../../../gpt4.json';
import MicrophonePlugin from 'wavesurfer.js/src/plugin/microphone';
declare module 'wavesurfer.js' {
interface WaveSurfer {
microphone: any;
}
}
@component({
selector: 'app-dialog-ia',
templateUrl: 'dialog-ia.component.html',
styleUrls: ['dialog-ia.component.scss'],
standalone: true,
imports: [
MatDialogModule,
MatButtonModule,
MatIconModule,
MatFormFieldModule,
MatInputModule,
QuillEditorComponent,
MatRippleModule,
MatTooltipModule,
MatCardModule,
MatToolbarModule,
MatButtonModule,
MatIconModule,
HttpClientModule,
MatStepperModule,
MatProgressBarModule,
MatDividerModule,
HighlightModule,
MatProgressSpinnerModule,
CommonModule
]
})
export class DialogIAComponent implements OnInit {
@ViewChild('spectrogram') spectrogramEl: ElementRef | undefined;
@ViewChild('waveform') waveformEl!: ElementRef;
@ViewChild('stepper') stepper!: MatStepper;
longText =
; mediaRecorder?: MediaRecorder; audioChunks: any[] = []; isRecording = false; audio?: HTMLAudioElement; displayedHtml =
;audioUrl: string | null = null;
isPlaying: boolean = false;
waveSurfer: WaveSurfer | null = null;
isGeneratingAudio = false;
chatMessage: string = this.data.texto;
voices: string[] = ['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'];
isAudioReady: boolean = false;
currentWordIndex: number = 0;
words: string[] = [];
isLoading: boolean = false;
//NLP
// Manipulação de Texto
textNLP: string = '';
pronouns: string[] = []; // Pronome
verbs: string[] = []; // Verbo
nouns: string[] = []; // Substantivo
adjectives: string[] = []; // Adjetivo
adverbs: string[] = []; // Advérbio
people: string[] = []; // Pessoas
places: string[] = []; // Lugares
organizations: string[] = []; // Organizações
dates: string[] = []; // Datas
values: string[] = []; // Valores
// Adicionando novas variáveis para funcionalidades adicionais
phrases: any[] = []; // Frases
clauses: string[] = []; // Cláusulas
negations: string[] = []; // Negativas
questions: string[] = []; // Perguntas
quotes: string[] = []; // Citações
acronyms: string[] = []; // Siglas
emails: string[] = []; // E-mails
urls: string[] = []; // URLs
emojis: string[] = []; // Emojis
mentions: string[] = []; // Menções (@usuario)
hashtags: string[] = []; // Hashtags
errorText = "";
constructor(
private http: HttpClient,
@Inject(MAT_DIALOG_DATA) public data: { texto: string },
private dialogRef: MatDialogRef,
) { }
ngOnInit() {
this.words = this.chatMessage.split(' ');
this.initWaveSurfer();
this.playSound();
this.performAnalysis();
}
/* ngAfterViewInit(): void {
this.waveSurfer = WaveSurfer.create({
container: this.waveformEl.nativeElement,
waveColor: '#d3d3d3',
progressColor: '#0000FF',
cursorColor: '#0000FF',
cursorWidth: 6,
barGap: 3,
barWidth: 2,
barHeight: 3,
barRadius: 10,
autoScroll: true,
autoCenter: true,
interact: true,
dragToSeek: true,
mediaControls: true, // controles
autoplay: true,
fillParent: true,
});
}
*/
/
/ setupWaveSurferEvents(): void {
if (!this.waveSurfer) return;
} */
/* setupWaveSurferEvents(): void {
// Configura o evento 'ready' para começar a reprodução automaticamente (opcional)
this.waveSurfer.on('ready', () => {
this.waveSurfer.play();
});
} */
// Método para iniciar a captura do áudio do microfone
startMicrophoneInput(): void {
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(stream => {
// Nota: Verifique a documentação do WaveSurfer.js para o método correto
// para carregar um MediaStream. Isso pode variar conforme a versão.
// Este exemplo supõe que você tenha um método apropriado.
//this.waveSurfer.loadStream(stream); // 'loadStream' é hipotético
})
.catch(err => console.error('Erro ao acessar o microfone:', err));
}
ngOnDestroy(): void {
// Limpeza para evitar vazamentos de memória
if (this.waveSurfer) {
this.waveSurfer.destroy();
}
}
ngAfterViewInit(): void {
this.waveSurfer = WaveSurfer.create({
container: this.waveformEl.nativeElement,
waveColor: 'violet',
progressColor: 'purple',
backend: 'WebAudio',
// Assegure-se de adicionar uma asserção de tipo aqui
plugins: [
MicrophonePlugin.create({}) // Usando 'as any' para contornar a verificação de tipo
]
});
this.activateMicrophonePlugin();
}
private activateMicrophonePlugin(): void {
if (this.waveSurfer && this.waveSurfer.microphone) {
// Ative o plugin de microfone como necessário
this.waveSurfer.microphone.start();
}
// Função para atualizar o HTML que será exibido
updateDisplayedHtml(htmlContent: string): void {
this.displayedHtml = htmlContent;
}
toggleRecording(): void {
this.isRecording ? this.stopRecording() : this.activateMicrophone();
this.isRecording = !this.isRecording;
}
activateMicrophone(): void {
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
this.mediaRecorder = new MediaRecorder(stream);
this.mediaRecorder.start();
this.audioChunks = [];
this.mediaRecorder.ondataavailable = event => {
this.audioChunks.push(event.data);
};
})
.catch(err => {
console.error('Could not access the microphone', err);
});
}
startRecording(): void {
if (!this.isRecording) {
this.activateMicrophone();
this.isRecording = true;
this.isLoading = true;
}
}
stopRecording(): void {
if (!this.mediaRecorder) {
return;
}
}
/* transcribeCurrentAudio() {
if (this.audioChunks.length > 0) {
const audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
this.transcribeAudio(audioBlob);
} else {
console.error('Nenhum áudio para transcrever');
}
} */
loadAudio(url: string): void {
this.audio = new Audio(url);
}
playSound(): void {
// Verifica se o áudio já foi gerado e está pronto para ser reproduzido
if (this.waveSurfer && this.isAudioReady) {
// Iniciar a reprodução do áudio
this.waveSurfer.play();
}
highlightWords(): void {
const interval = setInterval(() => {
// Verifica se todas as palavras foram destacadas
if (this.currentWordIndex >= this.words.length) {
clearInterval(interval); // Limpa o intervalo
return;
}
// Atualiza o HTML exibido com a palavra atual destacada
const highlightedText = this.words.slice(0, this.currentWordIndex + 1).join(' ');
this.updateDisplayedHtml(highlightedText);
// Move para a próxima palavra
this.currentWordIndex++;
}, 400); // Intervalo de 1 segundo entre cada palavra (ajuste conforme necessário)
}
pauseSound(): void {
if (this.audio && !this.audio.paused) {
this.audio.pause();
}
}
stopSound(): void {
if (this.audio) {
this.audio.pause();
this.audio.currentTime = 0;
}
}
closeDialog(): void {
this.dialogRef.close();
}
performAnalysis(): void {
// Atualiza textNLP com o valor de chatMessage
this.textNLP = this.chatMessage;
// Agora chama analyzeText para processar o texto
this.analyzeText();
}
analyzeText() {
const doc = nlp(this.chatMessage);
// Análise básica
this.pronouns = doc.pronouns().out('array');
this.verbs = doc.verbs().out('array');
this.nouns = doc.nouns().out('array');
this.adjectives = doc.adjectives().out('array');
this.adverbs = doc.adverbs().out('array');
this.people = doc.people().out('array');
this.places = doc.places().out('array');
this.organizations = doc.organizations().out('array');
this.clauses = doc.clauses().out('array'); // Cláusulas
this.questions = doc.questions().out('array'); // Perguntas
this.acronyms = doc.acronyms().out('array'); // Siglas
this.emails = doc.emails().out('array'); // E-mails
this.urls = doc.urls().out('array'); // URLs
}
//fim
}
`
Any advice or pointers towards the right approach to take or examples to follow would be greatly appreciated.
Thank you for your time and assistance.
Best regards,
Jose R F Junior
ps: my project , https://priming-ing.web.app/
Beta Was this translation helpful? Give feedback.
All reactions