Thread: Output to file: "1200,1300,1220,1220,"... ect.

  1. #1
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342

    Question Output to file: "1200,1300,1220,1220,"... ect.

    I want to make a program that will read a .WAV file and convert it into frequency readings like so:

    Output to file: "1200,1300,1220,1220,"... ect.

    I have it all done except the convertion part.
    (I have the .WAV file loaded in to a HSOUND var.)

    Thanks, August.

  2. #2
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    MSDN is coming up empy looking for a HSOUND type. What are you doing there ? Can you post some code ?
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  3. #3
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    This question (getting samples from a WAVE file) gets asked fairly often, usually without getting an answer. So I decided to cobble together some code.
    Code:
    /* 
       Code to retrieve sample values from a WAVE file.
       Mostly based on code from http://www.borg.com/~jglatt/tech/mmio.htm
    
       If not using MSVC, you must link with winmm.lib. In Dev-C++ do this
       by adding "-lwinmm" to the linker box under Project->Project Options->Parameters
       (you need to create a new project and add the code as a C file, if you haven't already).
    */
    
    #include <windows.h>
    #include <stdio.h>   /* Only required for sample code. */
    
    #if defined(_MSC_VER)
    #pragma comment(lib, "winmm.lib")
    #endif
    
    
    /*
     * Definition for the HXWAVE handle type. This structure should
     * be considered opaque.
     */
    typedef struct 
    {
    	WAVEFORMATEX WaveFormat;  /* Format of the wave file. */
    	HMMIO        hMmio;       /* Handle to the wave file. */
    	DWORD        cbDataChunk; /* Size of the wave data chunk. */
    } *HXWAVE;
    
    
    /*
     * Structure to contain a wave sample.
     */
    typedef struct
    {
    	USHORT left;
    	USHORT right;
    } XSAMPLE;
    
    
    /*
     * Open the wave file. The format must be one of the following:
     *     "PCM, 16 bit stereo"
     *     "PCM, 8  bit stereo"
     *     "PCM, 16 bit mono"
     *     "PCM, 8  bit mono"
     */
    HXWAVE xWaveOpen(LPCTSTR szFileName)
    {
    	MMCKINFO    mmckinfoParent;    /* parent chunk information structure */
    	MMCKINFO    mmckinfoSubchunk;  /* subchunk information structure */
    	HXWAVE      h;                 /* HXWAVE data structure */
    
    	/*   Allocate the wave handle. */
    	if (NULL == (h = (HXWAVE) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*h))))
    	{
    		/*   Oops, memory failure! */
    		goto error;
    	}
    
    	/*   Open the file for reading with buffered I/O. Let windows use its default internal buffer */
    	if (NULL == (h->hMmio = mmioOpen( (LPTSTR) szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF | MMIO_DENYWRITE)))
    	{
    		/*   Oops, file doesn't exist or access denied! */
    		goto error;
    	}
    
    	/*   Tell Windows to locate a WAVE FileType chunk header somewhere in the file.
    	 *   This marks the start of any embedded WAVE format within the file */
    	mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); 
    	if (MMSYSERR_NOERROR != mmioDescend(h->hMmio, (LPMMCKINFO) &mmckinfoParent, 0, MMIO_FINDRIFF)) 
    	{
    		/*   Oops! No embedded WAVE format within this file */
    		goto error;
    	} 
     
    	/*   Tell Windows to locate the WAVE's "fmt " chunk, and read in its size field */
    	mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' '); 
    	if (MMSYSERR_NOERROR != mmioDescend(h->hMmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK)) 
    	{
    		/*   Oops! The required fmt chunk was not found! */
    		goto error;
    	}
     
    	/*   Tell Windows to read in the "fmt " chunk into our WAVEFORMATEX structure */
    	if (mmioRead(h->hMmio, (HPSTR) &h->WaveFormat,
    	               min(mmckinfoSubchunk.cksize, sizeof(h->WaveFormat))) !=
    	               min(mmckinfoSubchunk.cksize, sizeof(h->WaveFormat)))
    	{
    		/*   Oops, couldn't read the format info! */
    		goto error;
    	}
     
    	/*   Check that we support the format. */
    	if (h->WaveFormat.wFormatTag != WAVE_FORMAT_PCM ||
    	    (h->WaveFormat.wBitsPerSample != 16 && h->WaveFormat.wBitsPerSample != 8) ||
                (h->WaveFormat.nChannels      != 1  && h->WaveFormat.nChannels      != 2))
    	{
    		/*   Oops, we don't handle this format! */
    		goto error;
    	}
    
    	/*   Ascend out of the "fmt " subchunk. If you plan to parse any other chunks in the file, you need to
    	 *   "ascend" out of any chunk that you've mmioDescend()'ed into */
    	mmioAscend(h->hMmio, &mmckinfoSubchunk, 0); 
    
    	/*   Tell Windows to locate the data chunk. Upon return, the file
    	 *   pointer will be ready to read in the actual waveform data within
    	 *   the data chunk */
    	mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); 
    	if (MMSYSERR_NOERROR != mmioDescend(h->hMmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK)) 
    	{
    		/*   Oops, couldn't find the data chunk! */
    		goto error;
    	}
     
    	/* Get the size of the data chunk (ie, the size of the waveform data) */
    	h->cbDataChunk = mmckinfoSubchunk.cksize;
    
    	return h;
    
    error:
    	if (h && h->hMmio) mmioClose(h->hMmio, 0);
    	if (h)             HeapFree(GetProcessHeap(), 0, h);
    	return NULL;
    }
    
    
    /*
     * Close the WAVE file.
     */
    VOID xWaveClose(HXWAVE hWave)
    {
    	mmioClose(hWave->hMmio, 0);
    	HeapFree(GetProcessHeap(), 0, hWave);
    }
    
    
    /*
     * Return the WAVEFORMATEX info for the specified file.
     */
    VOID xWaveGetFormat(HXWAVE hWave, WAVEFORMATEX* pFormat)
    {
    	CopyMemory(pFormat, &hWave->WaveFormat, sizeof(*pFormat));
    }
    
    
    /*
     * Read a sample into the structure pointed to by pSample.
     * All sample values are normalized to 16bit stereo.
     * Return Values:
     *     a return value greater than 0 indicates success.
     *     a return value of 0 indicates end of file.
     *     a return value of less than 0 indicates error.
     */
    LONG xWaveGetNextSample(HXWAVE hWave, XSAMPLE* pSample)
    {
    	/*   Read in left channel. */
    	LONG ret = mmioRead(hWave->hMmio, (HPSTR) &pSample->left, hWave->WaveFormat.wBitsPerSample / 8);
    
    	if (hWave->WaveFormat.nChannels == 2)
    	{
    		/*   Read in right channel, if it exists. */
    		ret = mmioRead(hWave->hMmio, (HPSTR) &pSample->right, hWave->WaveFormat.wBitsPerSample / 8);
    	}
    	else
    	{
    		/*   Mono file - give the right sample the same value as the left sample. */
    		pSample->right = pSample->left;
    	}
    
    	if (hWave->WaveFormat.wBitsPerSample == 8)
    	{
    		/*   Normalize unsigned 8 bit samples to 16 bit unsigned. */
    		pSample->left  *= 257;
    		pSample->right *= 257;
    	}
    	else
    	{
    		/*   Convert 16 bit signed samples to unsigned. */
    		pSample->left  = (SHORT) pSample->left  + 32768;
    		pSample->right = (SHORT) pSample->right + 32768;
    	}
    
    	return ret;
    }
    
    
    /*
     * Sample code (no error checking).
     * Dump samples to stdout in comma seperated values format.
     */
    int main(void)
    {
    	HXWAVE  hWave  = NULL;
    	XSAMPLE sample = { 0 };
    
    	hWave = xWaveOpen(TEXT("C:\\WINDOWS\\MEDIA\\TADA.WAV"));
    
    	while (xWaveGetNextSample(hWave, &sample) > 0)
    	{
    		printf("%u,%u\n", sample.left, sample.right);
    	}
    
    	xWaveClose(hWave);
    
    	return 0;
    }
    Testing was fairly minimal, so if you have any problems with the code, please post. The attached image shows the result of graphing every 40th sample of TADA.WAV with Excel.
    Last edited by anonytmouse; 11-16-2005 at 12:51 AM.

  4. #4
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    Thanks, anonytmouse, that explains how so many media programs out there do that.

  5. #5
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    Wait, I am getting some errors:

    Quote Originally Posted by Dev-C++ Compiler
    48 C:\Programming\WaveSamples\WaveSamples main.c non-local function `<anonymous struct>* xWaveOpen(const TCHAR*)' uses anonymous type
    132 C:\Programming\WaveSamples\WaveSamples main.c non-local function `void xWaveClose(<anonymous struct>*)' uses anonymous type
    142 C:\Programming\WaveSamples\WaveSamples main.c non-local function `void xWaveGetFormat(<anonymous struct>*, WAVEFORMATEX*)' uses anonymous type
    156 C:\Programming\WaveSamples\WaveSamples main.c non-local function `LONG xWaveGetNextSample(<anonymous struct>*, XSAMPLE*)' uses anonymous type
    I have never gotten errors like this before.
    Help?

    EDIT: I know that it sees HXWAVE* as an anonymous struct, how should I change that?
    Last edited by Queatrix; 11-17-2005 at 08:50 AM.

  6. #6
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    Now I got it to compile by changing:

    Code:
    typedef struct
    {
    public:
    	WAVEFORMATEX WaveFormat; /* Format of the wave file. */
    	HMMIO hMmio; /* Handle to the wave file. */
    	DWORD cbDataChunk; /* Size of the wave data chunk. */
    private:
    int i;
     
    } *HXWAVE;
    To:

    Code:
    typedef struct MyStruct
    {
    public:
    	WAVEFORMATEX WaveFormat; /* Format of the wave file. */
    	HMMIO hMmio; /* Handle to the wave file. */
    	DWORD cbDataChunk; /* Size of the wave data chunk. */
    } *HXWAVE;
    No errors,

    but the 'Program Error' message comes up.

  7. #7
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Weird, G++ requires a struct name, even though MSVC and GCC do not. I assume it is crashing because it can not open the file and there is no error checking. Add error checking as follows:
    Code:
    int main(void)
    {
    	HXWAVE  hWave  = NULL;
    	XSAMPLE sample = { 0 };
    
    	hWave = xWaveOpen(TEXT("C:\\WINDOWS\\MEDIA\\TADA.WAV"));
    
    	if (NULL == hWave)
    	{
    		fputs("Could not open WAVE file", stderr);
    		fputs("Please check that it exists and has the correct format.", stderr);
    		return -1;
    	}
    
    	while (xWaveGetNextSample(hWave, &sample) > 0)
    	{
    		printf("%u,%u\n", sample.left, sample.right);
    	}
    
    	xWaveClose(hWave);
    
    	return 0;
    }

  8. #8
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    Okay, that was it, wrong address to the wave file.

  9. #9
    Registered User
    Join Date
    Mar 2006
    Posts
    19
    Is anyone familiar with using the mmioWrite function, for example if i opened a wav file based this code and changed the line in mmioopen to MMIOREADWRITE. It would be easier then trying to create a brand new wav file and pass the values into it. What i'm trying to do is filter the left and right values found here
    Code:
    LONG xWaveGetNextSample(HXWAVE hWave, XSAMPLE* pSample)
    {
    	/*   Read in left channel. */
    	LONG ret = mmioRead(hWave->hMmio, (HPSTR) &pSample->left, hWave->WaveFormat.wBitsPerSample / 8);
    
    	if (hWave->WaveFormat.nChannels == 2)
    	{
    		/*   Read in right channel, if it exists. */
    		ret = mmioRead(hWave->hMmio, (HPSTR) &pSample->right, hWave->WaveFormat.wBitsPerSample / 8);
    	}
    	else
    	{
    		/*   Mono file - give the right sample the same value as the left sample. */
    		pSample->right = pSample->left;
    	}
    and place them back in the exact same place, so the size of the file won't be changing at all, thats why it might be simpler to do it this way. I looked up mmiowrite but can't figure it out, or how i could apply it to my problem. Is anyone out there able to help me?

  10. #10
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    Please don't bump old threads; just start a new thread with your question and put a link to the thread you want to refer to in your post.

    Quote Originally Posted by kermi3
    Welcome to the boards. If you haven't already done so then please take some time to familiarise yourself with the faq:
    http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

    Make sure you have a look at the the posting guidelines:
    http://cboard.cprogramming.com/annou...ouncementid=51
    Following the rules will ensure you get a prompt answer to your question.

    Remember, too, that the board has a search facility, a link is at the top of your screen:
    http://cboard.cprogramming.com/search.php
    It will often get you a quicker answer to your questions than waiting for a response to one you have posted.


    If you have any questions about this you may ask or you can contact one of our forum leaders:

    http://cboard.cprogramming.com/showgroups.php
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  11. #11
    Registered User
    Join Date
    Mar 2006
    Posts
    19
    sorry, will know in the future

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM
  2. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM
  3. what does this mean to you?
    By pkananen in forum C++ Programming
    Replies: 8
    Last Post: 02-04-2002, 03:58 PM
  4. Need a suggestion on a school project..
    By Screwz Luse in forum C Programming
    Replies: 5
    Last Post: 11-27-2001, 02:58 AM
  5. Simple File Creation Algorithm
    By muffin in forum C Programming
    Replies: 13
    Last Post: 08-24-2001, 03:28 PM