Line-in audio input amplitude is not static, Windows XP


  • I'm trying to develop a sound-card-based oscilloscope that reads line-in PCM audio data and displays it to a graph.  However, I am having trouble with the amplitude of the input data.

    First, I don't know how to determine the relationship between the input PCM data and the waveform data I am getting from the waveInXxx API.  If I change the volume slider of line-in in the audio mixer, the amplitude of the input waveform changes.  If I set line-in volume to its maximum, the input audio waveform will actually start clipping.  My audio data should be 16-bit, so I expected that the data would clip at about +/-32768, but instead it clips at about +/-13000.  This doesn't make any sense to me.

    Now I can arbitrarily set the line-in volume to some value (I picked 50%) using the Mixer API.  So this is what I have done.  I have a button on my GUI that calls a callback function, which runs the following code:


    			MMRESULT result;
    			HWAVEIN waveHandle;
    			WAVEFORMATEX waveFormat;
    			short int waveData[220500];
    			WAVEHDR waveHeader;
    			HMIXER mixerHandle;
    			MIXERLINE mixerLine;
    			MIXERLINECONTROLS mixerLineControls;
    			MIXERCONTROL mixerControl;
    			MIXERCONTROLDETAILS mixerDetails;
    			waveFormat.wFormatTag = WAVE_FORMAT_PCM; 	// standard uncompressed PCM
    			waveFormat.nChannels = 1;					// mono
    			waveFormat.nSamplesPerSec = 44100;			// 44.1 kHz sample rate
    			waveFormat.wBitsPerSample = 16;				// 16 bits per sample
    			waveFormat.nBlockAlign = 2;					// 2 bytes per sample
    			waveFormat.nAvgBytesPerSec = 88200;			// 44.1 kHz * 2 bytes per sample
    			waveFormat.cbSize = 0;						// no extra data appended for PCM
    			// open waveform audio input, no ACM
    			result = waveInOpen( &waveHandle, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_FORMAT_DIRECT );
    			// open mixer associated with waveform input
    			result = mixerOpen( &mixerHandle, (UINT)waveHandle, 0, 0, MIXER_OBJECTF_HWAVEIN );
    			mixerLine.cbStruct = sizeof(MIXERLINE);							// initialize size
    			mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;	// look for line-in source mixer line
    			// get line info about the line-in source mixer line
    			result = mixerGetLineInfo( (HMIXEROBJ)mixerHandle, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE );
    			mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);				// initialize size
    			mixerLineControls.dwLineID = mixerLine.dwLineID;					// line-in source mixer line ID
    			mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;	// look for volume control of line-in
    			mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);					// initialize size
    			mixerLineControls.cControls = 1;									// one control (volume)
    			mixerLineControls.pamxctrl = &mixerControl;							// assign control storage structure
    			// get the volume control of the line-in source mixer line
    			result = mixerGetLineControls( (HMIXEROBJ)mixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE );
    			mixerDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);			// initialize size
    			mixerDetails.dwControlID = mixerControl.dwControlID;			// line-in volume control ID
    			mixerDetails.cChannels = 1;										// one channel (mono)
    			mixerDetails.hwndOwner = 0;										// no window handle
    			mixerDetails.cMultipleItems = 0;								// no multiple items
    			mixerDetails.paDetails = &lineInVolume;							// assign volume storage structure
    			mixerDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);	// initialize size
    			lineInVolume.dwValue = 0x7FFF;									// set volume to this value (50%)
    			// set volume control of the line-in source mixer line
    			result = mixerSetControlDetails( (HMIXEROBJ)mixerHandle, &mixerDetails, MIXER_GETCONTROLDETAILSF_VALUE );
    			waveHeader.dwBufferLength = 5 * 88200;		// 5 seconds * 88200 bytes per second
    			waveHeader.dwFlags = 0;						// initialize flags to 0
    			waveHeader.lpData = (LPSTR)waveData;		// assign waveform data storage structure			
    			// prepare header
    			result = waveInPrepareHeader( waveHandle, &waveHeader, sizeof(waveHeader) );
    			// add buffer
    			result = waveInAddBuffer( waveHandle, &waveHeader, sizeof(waveHeader) );
    			// start recording
    			result = waveInStart( waveHandle );
    			// wait until recording is finished
    			while ( waveInUnprepareHeader ( waveHandle, &waveHeader, sizeof(waveHeader) ) == WAVERR_STILLPLAYING );
    			// close waveform input and mixer devices
    			result = waveInClose( waveHandle );
    			result = mixerClose( mixerHandle );
    			DeleteGraphPlot (panelHandle, PANEL_CHANNEL_LEFT, -1, VAL_IMMEDIATE_DRAW);
    			PlotWaveform (panelHandle, PANEL_CHANNEL_LEFT, waveData, 220500, VAL_SHORT_INTEGER,
    				1.0, 0.0, 0.0, 1.0/44100, VAL_THIN_LINE, VAL_NO_POINT, VAL_SOLID, 1, VAL_RED);

    However, even then, the amplitude of the input isn't constant.  In the next three samples, I am recording 5 seconds with no input to line-in, so I should record low-level white noise with constant amplitude.  But I get the following:

    Obviously, the amplitude is not constant.  It appears that there is some sort of AGC or compression going on.  What exactly is happening here?  For reference, I am using a Dell Latitude D620 with STAC9200 Sigma Tel audio codec.  Datasheet can be found at

    I am running Windows XP.  My compiler is LabWindows/CVI from National Instruments, so I can only use C, not C++.

    Any help is appreciated.


    14 февраля 2011 г. 16:43

Все ответы

  • When setting the MIXERCONTROLDETAILS_UNSIGNED for the volume of the wave input device- You are setting the signal strength of what will be recorded into the wavedata. The volume setting of the microphone is a specification of how much gain you wish to apply to the audio comming from the microphone. I use the microphone input to record audio, not the line-in. This is because line-in is not suppose to add any gain from the source audio, i.e the gain must be set externally from the audio source, e.g external CD player. Make sure that the device you are recording from isn't to loud, otherwise the signal will clip at 50%.

    28 июля 2011 г. 5:44