PDA

Ver la Versión Completa : Consulta para crear un vumetro/ecualizador


c64
06-12-2015, 05:30:22
Estube buscando informacion para crear un vumetro o algunos le llaman ecualizador. En definitiva el de la imagen que posteo.

http://www.digitaldjtips.com/wp-content/uploads/2011/09/vu-meters1.jpg

No entiendo mucho o muy poco, sobre el MCI o el DirectX, asi que me puse a buscar e intentar entender algo. Y esto es lo que mas o menos encontre (tenganme paciencia).

Encontre este tutorial soobre el MCI de windows. edn.embarcadero.com/article/28332#sthash.AuLj1Nc0.dpuf y encontre un lugar chino donde habian posteado parte del codigo, trastee para que ande y es lo que adjunto como zip abajo (esta funcionando).

En resumen Abre el MCI y lo configura si esto WS_VISIBLE esta comentado no lo muestra en pantalla.


m_hMCIWnd=MCIWndCreate(Handle,
g_hInstance,
// WS_VISIBLE |
WS_CHILD | WS_OVERLAPPED | WS_CAPTION | WS_BORDER |
MCIWNDF_RECORD | MCIWNDF_SHOWALL,
NULL );

Luego setea la configuracion a grabar (me olvide de cambiar los parametros antes de subirlo.


MCI_WAVE_SET_PARMS set_parms;
set_parms.wFormatTag = WAVE_FORMAT_PCM;
set_parms.wBitsPerSample = 16; // aca deberia ir 8
set_parms.nChannels = 1;
set_parms.nBlockAlign = (set_parms.nChannels*set_parms.wBitsPerSample)/8;
set_parms.nSamplesPerSec = 44100; // y aqui 11025


Deberian cambiarse porque en definitiva no nos interesa la calidad sino buscar los golpes en el audio, es decir cuando el buffer empieza a llenarse de informacion. Si en ese segundo sube de tamaño es que hay un golpe o sonido que puede mover el sonido.

Luego el codigo graba la informacion (y aqui nose como ni de donde toma los datos).


char file[260]="";

wsprintf(file,"a",GetTickCount()%100000L); // random filename

//
// now stop audio and save to disk
MCIWndStop(m_hMCIWnd);
MCIWndSave(m_hMCIWnd,file);
MCIWndClose(m_hMCIWnd);


En este momento estoy leyendo dos cosas esto para ver como funciona el MCI
msdn.microsoft.com/en-us/library/aa446573/

clubdelphi.com/foros/showthread.php?t=2020

Ok.. El tema es que no es solo una API, hay que abrir el canal , por ejemplo con waveInOpen si vamos a usar WaveIns, debes gestionar la memoria para los buffers de entrada (WaveInPrepareHeader y waveInAddBuffer) y con waveInStart empiezas a recibir datos en una CallBack.... Cuando finalices la operación hay que cerrar todo.
Este procedimiento CallBack recibe un los buffers, cuanto mas pequeños los crees, más se asemejara a "Tiempo Real", pero producirá que recaiga la performace de tu sistema. Si recorres este buffer puede encontrarte con los valores de sonido como para realizar un vúmetro.


Ahora... el código que utilizas para realizar la grabación debe utilizar winmm con la API waveInAddBuffer para obtener la onda en un vector; en tal caso y dependiendo del formato definido en waveInOpen podrás conocer el “valor de silencio”; por ejemplo... cuando utilizas PCM, mono y 1 byte por muestra; los valores de la onda son igual a Abs(v[i]-$80); en tal caso el silencio esta dado por un 128 +/- ruido.

El anterior caso varía dependiendo de los canales de grabacion, y los bytes por muestra.

y un ejemplo que postearon en este foro pero echo en delphi (lamentablemente no encuentro el link, lo subio como onda.zip).


if waveInOpen(@Device,WAVE_MAPPER,@wfx,Handle,0,CALLBACK_WINDOW) = MMSYSERR_NOERROR then
begin
BufferSize:= wfx.nBlockAlign * (wfx.nSamplesPerSec div BuffersPerSec);
Width:= BufferSize;
for i:= 1 to BuffersPerSec do
begin
GetMem(WaveBuffers[i],BufferSize);
with WaveHeaders[i] do
begin
lpData:= WaveBuffers[i];
dwBufferLength:= BufferSize;
dwBytesRecorded := 0;
dwUser := i;
dwFlags := 0;
dwLoops := 0;
lpNext := nil;
reserved := 0;
end;
end;
isDeviceOpen:= TRUE;
for i:= 1 to BuffersPerSec do
if waveInPrepareHeader(Device,@WaveHeaders[i],sizeof(TWAVEHDR))<>MMSYSERR_NOERROR then
begin
CloseWaveDevice;
exit;
end;
for i:= 1 to BuffersPerSec do
if waveInAddBuffer(Device,@WaveHeaders[i],sizeof(TWAVEHDR))<>MMSYSERR_NOERROR then
begin
CloseWaveDevice;
exit;
end;
waveInStart(Device);
end;
end;


La parte del grafico en si.


hdr:= PWaveHdr(Msg.LParam);
with hdr^ do
begin
P:= PByte(lpData);
Canvas.FillRect(Canvas.ClipRect);
Canvas.MoveTo(width,128);
Canvas.LineTo(0,128);
for i:= 1 to dwBytesRecorded do
begin
Canvas.LineTo(i,P^);
inc(P);
end;
end;


Creo que voy bien encaminado ahora estoy investigando como funciona el waveInOpen. Diganme que les parece el tema.

Otra manera de obtener audio es mediante directX, pero ahi estoy mas perdido aun.

c64
06-12-2015, 05:35:04
Adjunto un ejemplo que encontre (ruso) realizado en DirectX, aunque uso librerias externas aparentemente, es decir que no vienen instaladas en builder.

ecfisa
06-12-2015, 11:22:16
Hola c64.

Creo que vas a encontrar información interesante en los enlaces citados en este antiguo hilo del foro: Ecualizador (http://www.clubdelphi.com/foros/showthread.php?t=16647)

Saludos :)

c64
06-12-2015, 23:44:42
Hola c64.

Creo que vas a encontrar información interesante en los enlaces citados en este antiguo hilo del foro: Ecualizador (http://www.clubdelphi.com/foros/showthread.php?t=16647)

Saludos :)

Gracias ecfisa la pagina que me pasaste es relacionada a tratamiento de audio y plugins sobre programas segun vi, pero es bastante mas avanzado, no busco ecualizar la señal solo hacer el vumetro (buscar en los datos donde estan los golpes, que seria en el buffer cuando hay mas informacion (con eso ya me conformo). Buscando en internet encontre esto como para que vaya enriqueciendo el post.

Tratamiento a bajo nivel con DirectX y demas
http://wainu.ii.uned.es/ing_informatica/proyecto/PFC/otros/proyecto_audio_cpp.pdf

Tratamiento con la API de windows (como el ejemplo que subi)
http://www.dreamincode.net/forums/topic/208153-sound-recorder-using-the-low-level-windows-api-in-c/

Estoy agarrandole la mano al Builder, pero las API y Direct X son otra cosa totalmente distinta para mi.

Por cierto si alguno probo el codigo que subi arriba, y lo ejecuto, el archivo que genera es uno llamado a (sin extension ni nada), si lo renombran a a.wav ahi tendran el sonido en wav, no pude ponerle la extension ya que me tomaba el alfabeto asiatico nose porque.