[C++ API Win32] problema fruscio

di il
13 risposte

[C++ API Win32] problema fruscio

Salve, sto scrivendo un programma che registra e salva i suoni su un file;
funziona tutto bene ma quando vado ad ascoltare il file, oltre all'audio
registrato, si sente un fruscio.
Nel programma faccio uso di funzioni come waveOutOpen e mciSendCommand.

Esiste qualche modo per evitare questo fruscio? Grazie.

13 Risposte

  • Re: [C++ API Win32] problema fruscio

    Campionatura? codice usato? waveoutopen è solo una piccola parte e serve x out non per in.
  • Re: [C++ API Win32] problema fruscio

    Allora questo è il codice che ho usato:
    
    #include <windows.h>
    #include "resource.h"
    #pragma comment(lib, "Winmm.lib")
    
    #define DIM_BUFFER_INPUT 16384
    
    LRESULT CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
    
    TCHAR szNomeApp[] = TEXT("RegistratoreAudio");
    
    OPENFILENAME ofn;
    PBYTE pBuffer1, pBuffer2, pSalvaBuffer, pNuovoBuffer;
    PWAVEHDR pWaveHdr1, pWaveHdr2;
    HWAVEIN hWaveIn;
    HWAVEOUT hWaveOut;
    TCHAR szApriErrore[] = TEXT("Errore nell'apertura audio waveform!");
    TCHAR szMemErrore[] = TEXT("Errore nell'allocare la memoria!");
    WAVEFORMATEX waveform;
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
    	HWND hwnd;
    	MSG msg = {0};
    	WNDCLASS wndclass;
    
    	wndclass.style = CS_HREDRAW | CS_VREDRAW;
    	wndclass.lpfnWndProc = DialogProc;
    	wndclass.cbClsExtra = 0;
    	wndclass.cbWndExtra = DLGWINDOWEXTRA;
    	wndclass.hInstance = hInstance;
    	wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
    	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    	wndclass.lpszMenuName = NULL;
    	wndclass.lpszClassName = szNomeApp;
    
    	RegisterClass(&wndclass); //registrazione della classe
    
    	hwnd = CreateDialog(hInstance, szNomeApp, 0, NULL);
    
    	ShowWindow(hwnd, iCmdShow); //disegna la finestra sullo schermo, con le impostazioni iniziali date dall'utente
    
    	//ciclo dei messaggi
    	while(GetMessage(&msg, NULL,  0, 0)) //recupera un messaggio dalla coda (restituisce FALSE (0) solo per WM_QUIT)
    	{	
    		TranslateMessage(&msg);	//opera alcune modifiche al messaggio a seconda della tastiera
    		DispatchMessage(&msg);	//invia il messaggio alla window procedure appropriata
    	}
    	return  msg.wParam ;
    }
    
    void MostraErrore(HWND hwnd, DWORD dwErrore)
    {
    	TCHAR szStringErrore[1024];
    
    	//Ottiene il codice di errore mci
    	mciGetErrorString(dwErrore, szStringErrore, sizeof(szStringErrore) / sizeof(TCHAR));
    
    	MessageBeep(MB_ICONEXCLAMATION);
    	MessageBox(hwnd, szStringErrore, szNomeApp, MB_OK | MB_ICONEXCLAMATION);
    }
    
    void InitFile(HWND hwnd)
    {
    		static TCHAR szFiltro[] = TEXT("File wave (*.wav)\0*.wav\0") \
    								  TEXT("Tutti i files (*.*)\0*.*\0\0");
    
    		ofn.lStructSize = sizeof(OPENFILENAME);
    		ofn.hwndOwner = hwnd;
    		ofn.hInstance = NULL;
    		ofn.lpstrFilter = szFiltro;
    		ofn.lpstrCustomFilter = NULL;
    		ofn.nMaxCustFilter = 0;
    		ofn.nFilterIndex = 0;
    		ofn.lpstrFile = NULL; //Puntatore ad un buffer che riceve il nome del file qualificato completo (settato nelle funzioni Apri e Chiudi)
    		ofn.nMaxFile = MAX_PATH; //Dimensione del file
    		ofn.lpstrFileTitle = NULL; //Settato nelle funzioni Apri e Chiudi
    		ofn.nMaxFileTitle = MAX_PATH;
    		ofn.lpstrInitialDir = NULL;
    		ofn.lpstrTitle = NULL;
    		ofn.lpstrFileTitle = NULL; //Settato nelle funzioni Apri e Chiudi
    		ofn.Flags = 0; //Setta le opzioni per la finestra di dialogo (settato nelle funzioni Apri e Chiudi)
    		ofn.nFileOffset = 0;
    		ofn.nFileExtension = 0;
    		ofn.lpstrDefExt = TEXT("wav"); //Settato alla stringa di testo che contiene l'estenzione di default del nome del file se l'utente non ne specifica una
    		ofn.lpfnHook = NULL;
    		ofn.lpTemplateName = NULL;
    }
    
    BOOL SaveFileDlg(HWND hwnd, PTSTR pstrNomeFile, PTSTR pstrNomeTitolo)
    {
    		ofn.hwndOwner = hwnd;
    		ofn.lpstrFile = pstrNomeFile;
    		ofn.lpstrFileTitle = pstrNomeTitolo;
    		
    		//Il flag OFN_OVERWRITEPROMPT causa una finestra di messaggio che chiede all'utente se un file
    		//deve essere sovrascritto se il file selezionato già esiste
    		ofn.Flags = OFN_OVERWRITEPROMPT;
    
    		return GetSaveFileName(&ofn); //Mostra la finestra di dialogo Salva File
    }
    
    BOOL ScriviFile(HWND hwndEdit, PTSTR pstrNomefile)
    {
    		DWORD dwByteScritti;
    		HANDLE hFile;
    		int iLunghezza;
    		PTSTR pstrBuffer;
    		WORD wByteMark = 0xFEFF; //Byte order mark (serve per indicare che il file di testo contiene testo Unicode)
    
    		//Apre il file, lo crea se è necessario
    		if (INVALID_HANDLE_VALUE == (hFile = CreateFile(pstrNomefile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)))
    			return FALSE;
    
    		iLunghezza = GetWindowTextLength(hwndEdit); //Ottiene il numero di caratteri nell'edit control
    		pstrBuffer = (PTSTR)malloc((iLunghezza + 1) * sizeof(TCHAR)); //Alloca memoria per i caratteri nell'edit control
    
    		if (!pstrBuffer)
    			{
    				CloseHandle(hFile);
    				return FALSE;
    			}
    
    		//Se l'edit control restituisce il testo Unicode, scrive il byte wByteMark nel file
    		#ifdef UNICODE
    			WriteFile(hFile, &wByteMark, 2, &dwByteScritti, NULL);
    		#endif
    
    		GetWindowText(hwndEdit, pstrBuffer, iLunghezza + 1); //Ottiene il buffer di edit
    		WriteFile(hFile, &wByteMark, iLunghezza * sizeof(PBYTE), &dwByteScritti, NULL); //Scrive il buffer nel file
    
    		if ((iLunghezza * sizeof(TCHAR)) != (int)dwByteScritti)
    			{
    				CloseHandle(hFile);
    				free(pstrBuffer);
    				return FALSE;
    			}
    
    		CloseHandle(hFile);
    		free(pstrBuffer);
    
    		return TRUE;
    }
    
    LRESULT CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	static BOOL bRegistrare, bPlay, bInverti, bPausa, bFine, bTermina;
    	static DWORD dwLunghezzaDati, dwRipetizioni = 1;
    	
    	static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    	//static TCHAR szNomeFile[] = TEXT("record.wav");
    	static WORD wID_Device;
    	DWORD dwErrore;
    
    	//Contiene l'handle della finestra che riceve i messaggi di notifica (è usata per i messaggi di comando MCI che hanno le liste di parametri vuote; che non richiedono informazioni eccetto l'handle)
    	MCI_GENERIC_PARMS mciGenerico; 
    
    	MCI_OPEN_PARMS mciApri; //Contiene informazioni per il comando MCI_OPEN
    	MCI_PLAY_PARMS mciPlay; //Contiene le informazioni di posizionamento per il comando MCI_PLAY
    	MCI_RECORD_PARMS mciRegistra; //Contiene le informazioni di posizionamento per il comando MCI_RECORD
    	MCI_SAVE_PARMS mciSalva; //Contiene le informazioni del nome del file per il comando MCI_SAVE
    
    	switch(message)
    	{
    		case WM_CREATE:
    			InitFile(hwnd);
    			return 0;
    
    		case WM_INITDIALOG:
    			return TRUE;
    		
    		case WM_COMMAND:
    			switch(LOWORD(wParam))
    			{
    				case IDC_REGISTRA_INIZIO:
    					mciApri.dwCallback = 0;
    					mciApri.wDeviceID = 0;
    					mciApri.lpstrDeviceType = TEXT("waveaudio");
    					mciApri.lpstrElementName = TEXT("");
    					mciApri.lpstrAlias = NULL;
    
    					//Apre l'audio waveform
    					dwErrore = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)(LPMCI_OPEN_PARMS)&mciApri);
    
    					if(dwErrore != 0)
    					{
    						MostraErrore(hwnd, dwErrore);
    						return TRUE;
    					}
    
    					//Salva il Device ID
    					wID_Device = mciApri.wDeviceID;
    
    					mciRegistra.dwCallback = (DWORD)hwnd;
    					mciRegistra.dwFrom = 0;
    					mciRegistra.dwTo = 0;
    
    					//Inizia la registrazione (il flag MCI_NOTIFY causa un messaggio di notifica per essere spedito alla window procedure
    					//quando la registrazione è stata completata)
    					mciSendCommand(wID_Device, MCI_RECORD, MCI_NOTIFY, (DWORD)(LPMCI_RECORD_PARMS)&mciRegistra);
    
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_INIZIO), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_FINE), TRUE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_INIZIA), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_FINE), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSA), FALSE);
    
    					SetFocus(GetDlgItem(hwnd, IDC_REGISTRA_FINE));
    
    					bRegistrare = TRUE;
    					return TRUE;
    
    				case IDC_REGISTRA_FINE:
    					SaveFileDlg(hwnd, szFileName, szTitleName);
    
    					ScriviFile(hwnd, szFileName);
    
    					mciGenerico.dwCallback = 0;
    
    					//Ferma la registrazione
    					mciSendCommand(wID_Device, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGenerico);
    
    					mciSalva.dwCallback = 0;
    					mciSalva.lpfilename = szFileName;
    
    					//Salva il file waveform (trasferisce i dati del suono dal file temporaneo al file specificato record.wav)
    					mciSendCommand(wID_Device, MCI_SAVE, MCI_WAIT | MCI_SAVE_FILE, (DWORD)(LPMCI_SAVE_PARMS)&mciSalva);
    
    					//Elimina ogni file temporaneo o blocchi di memoria che possono essere stati
    					//creati e chiude il device waveform
    					mciSendCommand(wID_Device, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGenerico);
    					
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_INIZIO), TRUE);
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_FINE), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_INIZIA), TRUE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_FINE), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSA), FALSE);
    
    					SetFocus(GetDlgItem(hwnd, IDC_PLAY_INIZIA));
    
    					bRegistrare = FALSE;
    
    					return TRUE;
    
    				case IDC_PLAY_INIZIA:
    					waveform.wFormatTag = WAVE_FORMAT_PCM;
    					waveform.nChannels = 1;
    					waveform.nSamplesPerSec = 11025;
    					waveform.nAvgBytesPerSec = 11025;
    					waveform.nBlockAlign = 1;
    					waveform.wBitsPerSample = 8;
    					waveform.cbSize = 0;
    
    					//Apre l'audio waveform per l'output
    					if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, (DWORD)hwnd, 0, CALLBACK_WINDOW))
    					{
    						MessageBeep(MB_ICONEXCLAMATION);
    						MessageBox(hwnd, szApriErrore, szNomeApp, MB_ICONEXCLAMATION | MB_OK);
    					}
    
    					mciApri.dwCallback = 0;
    					mciApri.wDeviceID = 0;
    					mciApri.lpstrDeviceType = NULL;
    					mciApri.lpstrElementName = szFileName;
    					mciApri.lpstrAlias = NULL;
    					
    					//Apre l'audio waveform (il flag MCI_OPEN_ELEMENT indica che il campo lpstrElementName è un nome di file valido);
    					//il primo parametro (il Device ID) non viene usato con MCI_OPEN
    					dwErrore = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_ELEMENT, (DWORD)(LPMCI_OPEN_PARMS)&mciApri);
    
    					if(dwErrore != 0)
    					{
    						MostraErrore(hwnd, dwErrore);
    						return TRUE;
    					}
    
    					//Salva il Device ID
    					wID_Device = mciApri.wDeviceID;
    
    					mciPlay.dwCallback = (DWORD)hwnd;
    					mciPlay.dwFrom = 0;
    					mciPlay.dwTo = 0;
    
    					//Inizia la riproduzione del file waveform
    					mciSendCommand(wID_Device, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPMCI_PLAY_PARMS)&mciPlay);
    
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_INIZIO), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_FINE), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_INIZIA), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_FINE), TRUE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSA), TRUE);
    
    					SetFocus(GetDlgItem(hwnd, IDC_PLAY_FINE));
    
    					bPlay = TRUE;
    
    					return TRUE;
    
    				case IDC_PLAY_PAUSA:
    					if(!bPausa)
    					{
    						mciGenerico.dwCallback = 0;
    
    						//Mette in pausa
    						mciSendCommand(wID_Device, MCI_PAUSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGenerico);
    
    						SetDlgItemText(hwnd, IDC_PLAY_PAUSA, TEXT("Continua"));
    						bPausa = TRUE;
    					}
    					else
    					{
    						mciPlay.dwCallback = (DWORD)hwnd;
    						mciPlay.dwFrom = 0;
    						mciPlay.dwTo = 0;
    
    						//Ricomincia la riproduzione
    						mciSendCommand(wID_Device, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPMCI_PLAY_PARMS)&mciPlay);
    
    						SetDlgItemText(hwnd, IDC_PLAY_PAUSA, TEXT("Pausa"));
    						bPausa = FALSE;
    					}
    
    					return TRUE;
    
    				case IDC_PLAY_FINE:
    					bFine = TRUE;
    
    					//Resetta l'output per chiudere la preparazione (ferma la riproduzione e resetta la posizione corrente a 0)
    					waveOutReset(hWaveOut);
    
    					mciGenerico.dwCallback = 0;
    
    					//Ferma la riproduzione
    					mciSendCommand(wID_Device, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGenerico);
    
    					//Chiude il device waveform
    					mciSendCommand(wID_Device, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGenerico);
    
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_INIZIO), TRUE);
    					EnableWindow(GetDlgItem(hwnd, IDC_REGISTRA_FINE), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_INIZIA), TRUE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_FINE), FALSE);
    					EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSA), FALSE);
    
    					SetFocus(GetDlgItem(hwnd, IDC_PLAY_INIZIA));
    
    					bPlay = FALSE;
    					bPausa = FALSE;
    
    					return TRUE;
    				}
    
    				case MM_MCINOTIFY:
    					switch(wParam)
    					{
    						case MCI_NOTIFY_SUCCESSFUL:
    							if(bPlay)
    								SendMessage(hwnd, WM_COMMAND, IDC_PLAY_FINE, 0);
    
    							if(bRegistrare)
    								SendMessage(hwnd, WM_COMMAND, IDC_REGISTRA_FINE, 0);
    
    							return TRUE;
    					}
    					break;
    
    				case WM_DESTROY:
    					PostQuitMessage(0);
    					return 0;	
    			}
    			return DefWindowProc(hwnd, message, wParam, lParam);
    		}
    
    Ti sarei veramente grato se mi aiutassi a risolvere il problema.
    Ti ringrazio in anticipo.
  • Re: [C++ API Win32] problema fruscio

    Guarda la campionatura. Secondo te dov'è l'errore
    
    waveform.wFormatTag = WAVE_FORMAT_PCM;
    waveform.nChannels = 1;
    waveform.nSamplesPerSec = 11025;
    waveform.nAvgBytesPerSec = 11025;
    waveform.nBlockAlign = 1;
    waveform.wBitsPerSample = 8;
    waveform.cbSize = 0;
    
    Mono, 8 bit, 11025Hz.
  • Re: [C++ API Win32] problema fruscio

    Che valori devo inserire? Mi puoi dare qualche consiglio per cortesia?
  • Re: [C++ API Win32] problema fruscio

    Ma il codice è tuo o preso da qualche parte? il codice parla chiaro? nr canali (direi 2), nSample prova 44100, bitsxSample direi 16. Prova e vedi come si comporta. Io non programmo con MCI che sembra visual basic ma con le funzioni winmm vere e proprie.
  • Re: [C++ API Win32] problema fruscio

    Niente da fare, ho provato come mi hai detto ma il fruscio rimane.
  • Re: [C++ API Win32] problema fruscio

    Quale periferica stai cercando di registrare? Mi serve anche il codice del file .rc e resource.h.
    Non hai risposto alla mia domanda: il codice l'hai scritto tu?
  • Re: [C++ API Win32] problema fruscio

    Il codice l'ho preso da un libro, ma l'ho modificato e ho aggiunto delle nuove funzionalità.
    La perifica è il microfono del computer, il programma è simile al registratore di suoni
    di Windows.
    File .rc:
    
    #include <windows.h>
    #include "resource.h"
    
    //
    // Dialog resources
    //
    LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
    REGISTRATOREAUDIO DIALOG 100, 100, 186, 51
    STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
    CLASS "RegistratoreAudio"
    CAPTION "Registratore Audio"
    FONT 8, "Ms Shell Dlg"
    {
        PUSHBUTTON      "Registra", IDC_REGISTRA_INIZIO, 23, 8, 50, 14
        PUSHBUTTON      "Termina registrazione", IDC_REGISTRA_FINE, 88, 8, 75, 14, WS_DISABLED
        PUSHBUTTON      "Play", IDC_PLAY_INIZIA, 5, 29, 50, 14, WS_DISABLED
        PUSHBUTTON      "Pausa", IDC_PLAY_PAUSA, 67, 29, 50, 14, WS_DISABLED
        PUSHBUTTON      "Fine", IDC_PLAY_FINE, 131, 29, 50, 14, WS_DISABLED
    }
    
    IDI_ICON ICON "audio.ico"
    
    File .h:
    
    #define IDD_DIALOG1                             100
    #define IDC_PLAY_INIZIA                         1010
    #define IDC_PLAY_PAUSA                          1011
    #define IDC_PLAY_FINE                           1012
    #define IDC_REGISTRA_INIZIO                     1017
    #define IDC_REGISTRA_FINE                       1018
    #define IDI_ICON		                          1019
    
  • Re: [C++ API Win32] problema fruscio

    Fai questa prova.
    
    MCI_WAVE_SET_PARMS set_parms;
    set_parms.wFormatTag = WAVE_FORMAT_PCM;
    set_parms.wBitsPerSample = 16;
    set_parms.nChannels = 2;
    set_parms.nSamplesPerSec = 44100;
    set_parms.nAvgBytesPerSec = ((set_parms.wBitsPerSample)/8) *
                                                 set_parms.nChannels *
                                                 set_parms.nSamplesPerSec;
    set_parms.nBlockAlign = ((set_parms.wBitsPerSample)/8) *
                                         set_parms.nChannels;
    
    mciSendCommand( wID_Device, MCI_SET, MCI_WAIT |
                                MCI_WAVE_SET_FORMATTAG |
                                MCI_WAVE_SET_BITSPERSAMPLE |
                                MCI_WAVE_SET_CHANNELS |
                                MCI_WAVE_SET_SAMPLESPERSEC |
                                MCI_WAVE_SET_AVGBYTESPERSEC |
                                MCI_WAVE_SET_BLOCKALIGN,
                                (DWORD)(LPVOID)&set_parms);
    
    Aggiungi questo pezzo di codice nel case IDC_REGISTRA_INIZIO subito dopo l'acqusizione del deviceID, cioe dopo questa riga:
    wID_Device = mciApri.wDeviceID;
  • Re: [C++ API Win32] problema fruscio

    Si grazie, ora è molto meglio anche se il fruscio un po' ancora si sente.
  • Re: [C++ API Win32] problema fruscio

    Stai registrando dal microfono mica da un uscita ottica, cosa pretendi. Almeno hai la qualità di un mp3 decente.
  • Re: [C++ API Win32] problema fruscio

    L'hai provato anche tu?
  • Re: [C++ API Win32] problema fruscio

    No ma mi fido del codice
Devi accedere o registrarti per scrivere nel forum
13 risposte