Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008
-
13 oct. 2004 à 20:12
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008
-
19 oct. 2004 à 20:40
Bonjour je voudrais creer une application permettant d'analyser le flux audio sortant de la carte son, en ayant choisi le périphérique de capture et le canal d'enregistrement (entrée lign, master, cd , micro...).
Pour l'analyse je voudrais juste savoir comment récupérer 1 à 1 les samples sortant.
Je travaille sous devcpp en C# ( pas en cpp) donc j'ai bien vu plusieurs sources sur le site mais tout est bien trop compliqué par rapport à ce que je veux faire.
Le but final est de creer en module qui capture et trace la forme du signal sortant (sans le sauvegarder) et qui sache déterminer le tempo s'il existe du flux audio sélectionné. mais ma première question n'est pas si large, je veux juste connaitre le point de départ.
Funto66
Messages postés1267Date d'inscriptionmercredi 1 janvier 2003StatutMembreDernière intervention28 février 20074 13 oct. 2004 à 20:46
Tant qu'à faire je suis aussi intéressé par le pb, vu que ça serait sympa de pouvoir créer un multi-effets sur le PC qui pourrait agir en temps réel avec ma guitare (branchée sur la carte audio) :)
---------------------------------------------------------
Patience et longueur de temps font plus que force ni que rage....
Coucous flingueurs 3D : http://www.freewebs.com/cf3d/
Funto66
Messages postés1267Date d'inscriptionmercredi 1 janvier 2003StatutMembreDernière intervention28 février 20074 14 oct. 2004 à 18:08
Ah ben oui effectivement ça a l'air bien sympa :)
Ça pourra peut-être me servir si jamais je fais mon projet, merci ;)
---------------------------------------------------------
Patience et longueur de temps font plus que force ni que rage....
Coucous flingueurs 3D : http://www.freewebs.com/cf3d/
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 14 oct. 2004 à 23:37
Bon j'ai pas pu attendre le week-end,
J'ai un petit soucis, j'ai simplifié le code pour prendre qu'une petite partie qui m'interesse dans mon projet, j'ai une erreur lor de la compilation de cette partie:
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2; // Stereo
wfx.nSamplesPerSec = 22050; // Frequence d'echantillonnage
wfx.wBitsPerSample = 8; // Dynamique
wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8; // C'est MSDN qui l'a dit
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; // Ca aussi
// Ouverture de la carte son
if(waveInOpen(&hwi, 0, &wfx, (DWORD)hwnd, 0, CALLBACK_WINDOW)!= MMSYSERR_NOERROR)
{
MessageBox(hwnd, "Problème a l'ouverture de la carte son", "Erreur", MB_OK);
DestroyWindow(hwnd);
return 0;
}
[Linker error] undefined reference to `waveInOpen@24'
le problème c'est que cette erreur (plus une dizaine d'autre)apparait aussi dans le projet enregistreur de la source dont le lien a été donné par Matt67
J'ai vérifié j'ai bien le fichier mmsystem.h ou la fonction est énoncée.
Donc n'ayant pas de bases solide en c et sur windows je voudrais avoir votre avis sur la "source" du problème.
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 15 oct. 2004 à 21:49
Super, plus d'erreur, j'ai qd même eu du mal car je savais pas ce que c'est que "linker" mais là c bon, en plus avec devcpp la lib s'appelle libwinmm.a alors ça perturbe.
Bref maintenant que c'est passé j'ai un nouveau problème:
j'ai recopié le code interessant dans la source de l'enregistreur, en fait, juste la partie sur le tracé de l'oscilloscope, je n'ai pas d'erreur d'ouverture de carte son, tout se compile bien , le fond du scope se trace bien mais là problème quand la capture est lancée (c'est a dire à l'ouverture de la fenêtre pour moi) et bien il se passe .... rien. pas de trace de signal sur le graphe, même en sélectionnant les bons paramêtres d'enregistrement windows.
La fonction qui gère ma fenètre est la suivante:
LRESULT CALLBACK Capturesonproc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
if(waveInGetNumDevs() <= 0)
{
MessageBox(NULL, "Il faut un périphérique audio pour capturer le son", "Aucune carte son détectée...", MB_OK);
return 0;
}
// Preparation des formats pour la carte son
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2; // Stereo
wfx.nSamplesPerSec = 44100; // Frequence d'echantillonnage
wfx.wBitsPerSample = 16; // Dynamique
wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8; // C'est MSDN qui l'a dit
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; // Ca aussi
// Ouverture de la carte son
if(waveInOpen(&hwi, 0, &wfx, (DWORD)hwnd, 0, CALLBACK_WINDOW)!= MMSYSERR_NOERROR)
{
MessageBox(hwnd, "Problème a l'ouverture de la carte son", "Erreur", MB_OK);
return 0;
}
case MM_WIM_OPEN:
// Demarrage de la carte son
waveInStart(hwi);
return 0;
case MM_WIM_DATA:
// On incremente la ProgressBar s'il y a des donnees
// On copie dans un buffer temporaire pour la representation graphique
CopyMemory(BufferTmp, ((PWAVEHDR)lParam)->lpData, ((PWAVEHDR)lParam)->dwBytesRecorded);
InvalidateRect(hwnd, &rect, TRUE);
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
HPEN hp; // Scope
HBRUSH hb; // Fond du scope
LOGBRUSH lb; // Style de la brush
short xScale, yScale, Zero; // Pour les differentes echelles size_t i 0, k 0; // Pour les boucles et les indices
// On met a l'echelle de la fenetre
rect.left = 0;
rect.top = 0;
rect.right = 310;
rect.bottom = 60;
// debut de x pour le dessin
k = rect.left;
// Determination du zero de l'oscillo
Zero = (rect.top + rect.bottom) / 2;
// Determination des echelles
xScale = (TAILLE_BUFFER / 2) / (rect.right - rect.left);
yScale = (32767 / (rect.top - Zero));
// Structure pour la brush
lb.lbStyle = BS_SOLID;
lb.lbColor = 0x00000000;
// On recupere le DC de la fenetre
hdc = BeginPaint(hwnd, &ps);
// Creation de PEN et de BRUSH
hp = CreatePen(PS_SOLID, 1, 0x0000FF00);
hb = CreateBrushIndirect(&lb);
// On les selectionne
SelectObject(hdc, hp);
SelectObject(hdc, hb);
// On dessine le fond du scope
Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
// On pose le premier point
MoveToEx(hdc, k++, Zero - (BufferTmp[0]/yScale), NULL);
for(i=1; i<(TAILLE_BUFFER / 2); i+=xScale)
{
// On dessine les echantillons
LineTo(hdc, k++, Zero - (BufferTmp[i]/yScale));
}
// On suprime les objets
DeleteObject(hb);
DeleteObject(hp);
// Fin du dessin
EndPaint(hwnd, &ps);
return 0;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_BUTTON_CLOSESOUND:
DestroyWindow(Soundwindow);
}
default:
/* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
cs_Matt67
Messages postés549Date d'inscriptionsamedi 6 septembre 2003StatutMembreDernière intervention 6 mars 20103 16 oct. 2004 à 13:01
Bonjour
Bon, la il faut y aller petit a petit...
Est ce que le message MM_WIM_DATA est bien posté...
Si oui regarde se qu'il y a dans ton buffertmp pour voir s'il n'est pas vide...
Si pas vide alors ca doit venir de ton message WM_PAINT.
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 16 oct. 2004 à 13:29
j'ai casé deux petites messagesbox dans les parties des messages wim open et wim data, et bien j'ai deux fois la wimopen qui apparait avant que la fenêtre s'affiche mais pas de trace de wimdata.
:
case MM_WIM_OPEN:
// Demarrage de la carte son
waveInStart(hwi);
MessageBox(hwnd, "wimopen", "COOL", MB_OK);
waveInAddBuffer(hwi, ((PWAVEHDR)lParam), sizeof(WAVEHDR));
return 0;
case MM_WIM_DATA:
// On incremente la ProgressBar s'il y a des donnees
// On copie dans un buffer temporaire pour la representation graphique
CopyMemory(BufferTmp, ((PWAVEHDR)lParam)->lpData, ((PWAVEHDR)lParam)->dwBytesRecorded);
InvalidateRect(hwnd, &rect, TRUE);
MessageBox(hwnd, "wimdata", "COOL", MB_OK);
return 0;
Ce message wimdata est posté par qui ?
Question en plus : comment je peux verrifier si j'ai quelquechose dans mon buffer ?
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 17 oct. 2004 à 11:27
Voilà c'est bon ça marche, j'ai fini à 1h mais ça marche. J'ai changé le type de scope maintenant c'est une trace défilante.
J'ai encore deux ou trois questions sur le code en lui même:
Pourquoi on met 2 ou 4 buffer "Buffer[i]" et un buffer temporaire "BufferTmp" alors que n'utilise que que BufferTmp. Est-ce qu'ils servent réellement dans mon cas ou est-ce que c'était juste pour la sauvegarde des fichiers ?
Pourquoi on voit partout TAILLE_BUFFER / 2 et pourquoi il semble que les buffers soient remplis qu'a moitié à chaque fois.
Dernière chose: Dans un buffer les derniers échantillons à être passé sont du coté des indices BufferTmp[0],BufferTmp[1]... ou plutôt sur la fin du Buffer BufferTmp[TAILLE_BUFFER/2], BufferTmp[TAILLE_BUFFER/2 - 1]... (c'est pour savoir si je trace mon graphe dans le bon sens.
Bon allé juste une dernière, y'a pas un truc pour empécher le graphe de scintiller ? je suis à un rafraichissement d'environ 22Hz et y'a des trucs bizarre qui apparaissent.
Voilà et encore merci, une fois finalisé je posterais la source pour que tu vois ce que ça donne.
cs_Matt67
Messages postés549Date d'inscriptionsamedi 6 septembre 2003StatutMembreDernière intervention 6 mars 20103 17 oct. 2004 à 12:21
Salut,
Bon dans l'ordre :
En fait, s'il n'y a qu'1 buffer tu risques de perdre des echantillons...
Il en faut 2 au minimum (pas obligatoire) car pendant qu'il y en a un en enregistrement, tu peux traiter l'autre (copie du buffer, affichage, filtrage, fft ...)
BufferTmp c'est que tu ne traites pas directement avec le buffer de capture... Tu copies le buffer de capture et hop tu le remet dans la file.
(double securité avec ce que j'ai dit au dessus).
TAILLE_BUFFER / 2 parce que je travail sur une dynamique de 16 bits donc 2 octets...
Le buffer de capture fait 4096 octets et je n'ai que 2048 échantillons.
Buffer[TAILLE_BUFFER - 1] est le dernier échantillon enregistré.
Pour le scintillement, faut voir le source. Quand tu l'auras posté, fait mon le savoir et je regarderai mais pas sur que je trouverai le probleme (c'est quoi ta machine ???)
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 17 oct. 2004 à 17:10
Machine: portable sous XP, P4 2,8GHz, nvidia Geforce 4 128MO donc ça vien pas de là le scintillement, les 22hz c'est le rafraichissement du graph.
Voilà j'ai fait quelquechose de sympa avec mise à l'échelle du graphe automatique, détermination des beats de la musique, affichage de la moyenne du signal....
ça marche .... pendant 2 minutes puis après je sais pas ce qui ce passe, le graphe devient noir mes fenêtres ne se dessinent plus correctement (elle laissent quelquefois de traces sur elles-même bizarre). J'ai essayé de bouger la remise du buffer dans la queue
et la mettre juste après sa copie mais ça ne change rien (ça marche toujours).
J'ai l'impression que j'utilise pas les buffers supplémentaires je vois pas où je les copy, je vois que la copie du PWAVEHDR dans bufferTmp.
ça pourrait venir de là ? un "buffer underrun" pitet.
Voilà la source de ma procédure (petite procédure deviendra grande...):
LRESULT CALLBACK Capturesonproc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{ long sum;
short speed; size_t i 0, k 0, j=0;
switch (message)
{
case WM_CREATE:
if(waveInGetNumDevs() <= 0)
{
MessageBox(NULL, "Il faut un périphérique audio pour capturer le son", "Aucune carte son détectée...", MB_OK);
return 0;
}
// On incremente la ProgressBar s'il y a des donnees
// On copie dans un buffer temporaire pour la representation graphique
CopyMemory(BufferTmp, ((PWAVEHDR)lParam)->lpData, ((PWAVEHDR)lParam)->dwBytesRecorded);
waveInAddBuffer(hwi, ((PWAVEHDR)lParam), sizeof(WAVEHDR));
//on calcule une vitesse de défilement
speed=TAILLE_BUFFER/9;
//On reli la mémoire des 310 dernières moyennes d'échantillons
// et de valeur du beat on les décale pour laisser la place aux nouvelles valeurs
}
//On fait baisser le max automatiquement (sert pour l'echelle du graphique)
max=(2*max+7000)/3;
//On fait baisser la valeur moyenne du signal automatiquement
moyenne=(20*moyenne+12000)/21;
//et on les réajuste en conséquense.
sum=0;
for(i=0; i<=310; i++){
sum+=sound[i];
if(sound[i]>max){max=(2*max+sound[i])/3;}
}
if((sum/310)>moyenne){moyenne=(sum/310);}
//là on lit le buffer on fait la moyenne de groupes d'échantillons
for(i=0; i<(TAILLE_BUFFER / (2*speed)); i++)
{
sum=0;
for(k=speed*i; k<speed*(i+1); k++)
{
sum+=abs(BufferTmp[k]);
}
sum=sum/(speed);
sound[310-(TAILLE_BUFFER / (2*speed))+i]=(3*sound[310-(TAILLE_BUFFER / (2*speed))+i-1]+sum)/4;
//puis on procède à la détection du beat
sum=0;
for(j=0; j<10; j++){sum+=sound[310-(TAILLE_BUFFER / (2*speed))+i-j];}
sum=sum/10;
//on retrace le graphe
InvalidateRect(hwnd, &rect, TRUE);
return 0;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
HPEN hp; // Scope
HBRUSH hb; // Fond du scope
LOGBRUSH lb; // Style de la brush
short xScale, yScale; // Pour les differentes echelles
// Pour les boucles et les indices
// On met a l'echelle de la fenetre
rect.left = 0;
rect.top = 0;
rect.right = 310;
rect.bottom = 67;
// Structure pour la brush
lb.lbStyle = BS_SOLID;
lb.lbColor = 0x00000000;
// On recupere le DC de la fenetre
hdc = BeginPaint(hwnd, &ps);
// Creation de PEN et de BRUSH
hp = CreatePen(PS_SOLID, 1, 0x0000FF00);
hb = CreateBrushIndirect(&lb);
// On les selectionne
SelectObject(hdc, hp);
SelectObject(hdc, hb);
// On dessine le fond du scope
Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
DeleteObject(hb);
DeleteObject(hp);
// Fin du dessin
EndPaint(hwnd, &ps);
sum=0;
UpdateWindow (Soundwindow);
return 0;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_BUTTON_CLOSESOUND:
DestroyWindow(Soundwindow);
case ID_BUTTON_BEGINSYNCHRO:
// Preparation des formats pour la carte son
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 1; // Stereo
wfx.nSamplesPerSec = 11025; // Frequence d'echantillonnage
wfx.wBitsPerSample = 16; // Dynamique
wfx.nBlockAlign = 11025; // C'est MSDN qui l'a dit
wfx.nAvgBytesPerSec = 11025; // Ca aussi
// Ouverture de la carte son
if(waveInOpen(&hwi, 0, &wfx, (DWORD)hwnd, 0, CALLBACK_WINDOW|WAVE_FORMAT_DIRECT)!= MMSYSERR_NOERROR)
{
MessageBox(hwnd, "Problème a l'ouverture de la carte son", "Erreur", MB_OK);
return 0;
}
}
default:
/* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
et dans mon main.h il y a:
#define NB_BUFFER 2
#define TAILLE_BUFFER 500
cs_Matt67
Messages postés549Date d'inscriptionsamedi 6 septembre 2003StatutMembreDernière intervention 6 mars 20103 18 oct. 2004 à 08:58
Essai de mettre une TAILLE_BUFFER un peu plus grande car tu as une Fe de 11025 et une taille buffer de 500 octets donc 250 echantillons...
cela fait que tu as un buffer qui tombe toute les 20 ms et peut être que ton traitement (copy, mise a l'echelle, dessin ...) prend un peu plus de temps que ca, donc au bout d'un moment ca plante ???
Pour ce qui est des buffers c'est géré automatiquement...
un buffer se rempli, puis le message est posté et quand tu fais waveInaddBuffer avec les bons parametres tu le remet dans la file et ainsi de suite. Pour etre correct, il faudrait regarder les buffers qui tombent et voir s'ils bien dans l'ordre pour voir s'il n'y a pas un décalage.
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 18 oct. 2004 à 17:39
Bon y'a une bonne nouvelle, c'est que ça vient pas de l'audio, enfin en tout cas peut-être pas de la manière que l'on pense.
J'aiessayé avec des buffers plus gros, du coup j'ai moins de fps du graphe c'est moins fluide, mais ça plante toujours, faut juste plus longtemp.
De plus une fois que ça a planté c'est a dire que le graphe ne donne plus signe de vie, il suffit de faire bouger la fenêtre (dont la barre de titre se met à faire n'importe quoi) pour voir le graphe se retracer en clignotant, puis dès que l'on arrète de bouger la fenêtre le graphe ne se redessine plus. En fermant et en rouvrant
cette fenêtre dans le logiciel ça n'arrange pas le problème, il faut complètement redémarrer le logiciel et ça repart (même si c'est pas Mars, désolé les nerf lachent...).
Donc j'ai pensé à quelquechose, à deux choses en fait:
Soit je vous laisse tranquille avec mon problème et je vais poser ma question dans la partie graphique et essayant de changer la méthode d'affichage (double buffering par exemple, que je ne sais pas faire non-plus mais ça n'a pas l'air mal).
Soit on essaye de continuer ici, comme vous commencez à connaitre un peu ma source.
Dans tous les cas vous m'avez déjà fortement aidé et je vous en remercie. Si vous voulez continuer à m'aider ça serait encore mieux mais je ne voudrais pas abuser.
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 18 oct. 2004 à 19:40
Les erreurs je me doute que je dois en faire plein, il s'agit là de mon tout premir programme, même pas de petit hello world.
Je compile aussi avec dev cpp.
Pour les fenêtre moi je veux bien mettre des boites de dialogue mais j'avais pas réussi donc j'ai mis tout en fenetre, mais ce que j'aimerais c'est qu'elles soient vraiment dépendante de la principale, c'est à dire qu'elles restent toutes actives quand l'application est active et qu'elles bougent avec la principale quand on la déplace.
Sinon pour le problème j'ai pensé à un truc: peut-être qu'a force de créer des objets paintstruct hdc et autre sans les détruire on arrive à un maximum et que ça pose un problème, enfin là je connais pas encore grand chose alors je dis ce qui me passe par la tête.
Sinon je vais essayer un autre mode d'affichage, qui ne serait plus dépendant du buffer audio au niveau du rafraichissement.
En tout cas merci pour la correction des bugs.
Je vais faire un essai avec bitblt, c'est à dire que je vais dessiner hors de l'écran et afficher après. Je vais certainement avoir quelques soucis alors ne reste pas trop loin lol...
Mastersam
Messages postés116Date d'inscriptiondimanche 26 septembre 2004StatutMembreDernière intervention13 février 2008 18 oct. 2004 à 23:10
Voilà j'ai refait quelquechose avec bitblt dont j'avais entendu parlé et déjà utilisé pour une image bitmap.
Je peux pas encore juger si ça foire car je n'ai pas d'erreur mais
je n'ai rien qui s'affiche.
Voilà mon paint:
case WM_PAINT:
{
HDC hdc;
HDC hdcMemory;
PAINTSTRUCT ps;
HPEN hp; // Scope
HBRUSH hb; // Fond du scope
LOGBRUSH lb; // Style de la brush
short xScale, yScale; // Pour les differentes echelles
// Pour les boucles et les indices
// On met a l'echelle de la fenetre
rect.left = 0;
rect.top = 0;
rect.right = 310;
rect.bottom = 67;
// Structure pour la brush
lb.lbStyle = BS_SOLID;
lb.lbColor = 0x00000000;
// On recupere le DC de la fenetre
hdc = BeginPaint(hwnd, &ps);
// Creation de PEN et de BRUSH
hp = CreatePen(PS_SOLID, 1, 0x0000FF00);
hb = CreateBrushIndirect(&lb);
hdcMemory=CreateCompatibleDC(NULL);
// On les selectionne
SelectObject(hdcMemory, hp);
SelectObject(hdcMemory, hb);
// On dessine le fond du scope
Rectangle(hdcMemory, rect.left, rect.top, rect.right, rect.bottom);
for(i=1; i<310; i++)
{
MoveToEx(hdcMemory, i,rect.bottom-(6*beat[i]), NULL);
LineTo(hdcMemory, i,rect.bottom-7-(sound[i]/(max/60)));
}
hp = CreatePen(PS_SOLID, 1, 0x00FF0000);
SelectObject(hdc, hp);
if(moyenne<max)
{
MoveToEx(hdcMemory, 0,rect.bottom-7-moyenne/(max/60), NULL);
LineTo(hdcMemory, 310,rect.bottom-7-moyenne/(max/60));
}
hp = CreatePen(PS_SOLID, 1, 0x0055FFFF);
SelectObject(hdc, hp);
if(moyenne+limithi<max)
{
MoveToEx(hdcMemory, 0,rect.bottom-7-(moyenne+limithi)/(max/60), NULL);
LineTo(hdcMemory, 310,rect.bottom-7-(moyenne+limithi)/(max/60));
}
if(moyenne+limitlow<max)
{
MoveToEx(hdcMemory, 0,rect.bottom-7-(min)/(max/60), NULL);
LineTo(hdcMemory, 310,rect.bottom-7-(min)/(max/60));
}
// Fin du dessin
BitBlt(hdc,0,0,rect.right,rect.bottom,hdcMemory,0,0,SRCCOPY);
Je voit pas trop ce que j'ai mal fait car ça marche avec une image plus bas dans mon code, et là, rien.
J'ai réenvoyé la source à jour : Source et exe J'en ai profité également pour désactiver le bouton sychro quand il a été cliqué et l'inverse pour le stop qui logiquement est devenu fonctionnel.