I need a way for a BCB app to monitor and display the current wave out audio level on both left and right channels (or mono). The level (volume) will be changing as system sounds are played and other music apps play stuff. Is there a Win API method for getting its value? I have already got an MM timer ready for its use, set at 50ms refresh. Please help. -- Mark Jacobs
> I need a way for a BCB app to monitor and display the current wave out audio > level on both left and right channels (or mono). The level (volume) will be > changing as system sounds are played and other music apps play stuff. Is > there a Win API method for getting its value? I have already got an MM timer > ready for its use, set at 50ms refresh. Please help.
You don't want the volume - that's the value of the 'volume control' Look for MIXERCONTROL which defines xxx_CLASS_METER for different Audio channels(Lines) and also mixerGetLineControls() which is used to get the information. (BTW I've never done this so I'm just searchng help) Do look at www.torry.net as they have several controls for doing similar things. I've seen audio metering components there - just can't remember where :(
I have looked, tried, tinkered and fretted. I do not know whether to open waveIn or waveOut in order to monitor currently playing levels. I keep getting "An invalid flag was passed to a system function." (code 10) from the following code :- //------------------------------------------------------------------------- -- void __fastcall TForm1::zcMMTimer1Timer(TObject *Sender) { char erst[199]; unsigned long vl; HWAVEOUT phwo; MMRESULT wh; WAVEFORMATEX pwfx; zcMMTimer1->Enabled=false; erst[0]='\0'; pwfx.wFormatTag=WAVE_FORMAT_PCM; pwfx.nChannels=2; pwfx.nSamplesPerSec=44100; pwfx.nAvgBytesPerSec=44100*2*16/8; pwfx.nBlockAlign=2*16/8; pwfx.wBitsPerSample=16; pwfx.cbSize=0; wh=waveOutOpen(&phwo,WAVE_MAPPER,&pwfx,0,0,WAVE_MAPPED); if (wh!=MMSYSERR_NOERROR) { waveOutGetErrorText(wh,erst,190); Edit3->Text="Error="+AnsiString(erst); return; // intentionally leaving the timer disabled } waveOutGetVolume(phwo,&vl); waveOutClose(phwo); zcDinMeter1->Value=(vl & 0xFFFF); zcDinMeter2->Value=((vl & 0xFFFF0000)>>16); Edit3->Text="L:"+mjfmtnm(vl & 0xFFFF)+" R:"+mjfmtnm((vl & 0xFFFF0000)>>16); zcMMTimer1->Enabled=true;
If I change the waveOutOpen line to read :- wh=waveOutOpen(&phwo,0,&pwfx,0,0,WAVE_MAPPED); I get both channels maxed out constantly, whether there is sound or not.
The timer is firing 10 times a second. I am floundering - please help. -- Mark Jacobs DK Computing http://www.dkcomputing.co.uk ma...@criticalremovethisspuriousantispamstuff.co.uk
"Pete Fraser" <pete._no_spam_fra...@frasersoft.nospam.net> wrote in message
> Yes there is. Look in the multimedia API help files under SDK help on > Borland Start menu > "Mark Jacobs" <m...@losethisbitjacobsm.com> wrote in message > news:4069d98a@newsgroups.borland.com... > > I need a way for a BCB app to monitor and display the current wave out > audio > > level on both left and right channels (or mono). The level (volume) will > be > > changing as system sounds are played and other music apps play stuff. Is > > there a Win API method for getting its value? I have already got an MM > timer > > ready for its use, set at 50ms refresh. Please help.
I have changed my code to use mixer api, but I *cannot* set any control type except MIXERCONTROL_CONTROLTYPE_VOLUME, and the values reflect where I am sliding the Wave volume control, when you double-click the speaker icon in your system tray. So the code works after a fashion, but I cannot set anything but MIXERCONTROL_CONTROLTYPE_VOLUME. I have tried MIXERCONTROL_CONTROLTYPE_SIGNEDMETER and MIXERCONTROL_CONTROLTYPE_PEAKMETER and they both give error 1025 - the control specified is not valid. What is going on? Why doesn't this work? Please help. Here is my code :- //------------------------------------------------------------------------- -- void __fastcall TForm1::zcMMTimer1Timer(TObject *Sender) { unsigned int vl,mxi; char erst[199]; int mcierr; zcMMTimer1->Enabled=false; erst[0]='\0'; HMIXER hmx; MIXERCONTROLDETAILS mxd; MIXERCONTROLDETAILS_SIGNED chinf[2]; MIXERLINE mxl; MMRESULT wh; MIXERLINECONTROLS mxlcs; MIXERCONTROL mxctl; if (waveOutGetNumDevs()<1) return; Edit3->Text="Opening Mixer..."; wh=mixerGetID(0,&mxi,MIXER_OBJECTF_WAVEOUT); if (wh!=MMSYSERR_NOERROR) { Edit3->Text=Edit3->Text+" - Error="+AnsiString(wh); return;} wh=mixerOpen(&hmx,mxi,0,0,MIXER_OBJECTF_WAVEOUT); if (wh!=MMSYSERR_NOERROR) { Edit3->Text=Edit3->Text+" - Error="+AnsiString(wh); return;} mxl.cbStruct=sizeof(MIXERLINE); mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT; Edit3->Text="Getting mixer line details..."; wh=mixerGetLineInfo(hmx,&mxl,MIXER_GETLINEINFOF_COMPONENTTYPE); if (wh!=MMSYSERR_NOERROR) { Edit3->Text=Edit3->Text+" - Error="+AnsiString(wh); return;} Edit3->Text="Getting mixer line controls..."; mxlcs.cbStruct=sizeof(MIXERLINECONTROLS); mxlcs.dwLineID=mxl.dwLineID; mxlcs.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME; mxlcs.cControls=1; mxlcs.cbmxctrl=sizeof(MIXERCONTROL); mxlcs.pamxctrl=&mxctl; wh=mixerGetLineControls(hmx,&mxlcs,MIXER_GETLINECONTROLSF_ONEBYTYPE); if (wh!=MMSYSERR_NOERROR) { Edit3->Text=Edit3->Text+" - Error="+AnsiString(wh); return;} Edit3->Text="Getting volume levels..."; mxd.cbStruct=sizeof(MIXERCONTROLDETAILS); mxd.dwControlID=mxctl.dwControlID; mxd.cChannels=mxl.cChannels; mxd.hwndOwner=NULL; mxd.cMultipleItems=0; mxd.cbDetails=sizeof(MIXERCONTROLDETAILS_SIGNED); mxd.paDetails=chinf; wh=mixerGetControlDetails(hmx,&mxd,MIXER_GETCONTROLDETAILSF_VALUE); if (wh!=MMSYSERR_NOERROR) { Edit3->Text=Edit3->Text+" - Error="+AnsiString(wh); return;} Edit3->Text="L:"+mjfmtnm(chinf[0].lValue)+" R:"+mjfmtnm(chinf[1].lValue); mixerClose(hmx); zcMMTimer1->Enabled=true;
}
//------------------------------------------------------------------------- -- -- Mark Jacobs DK Computing http://www.dkcomputing.co.uk ma...@criticalremovethisspuriousantispamstuff.co.uk
"Pete Fraser" <pete._no_spam_fra...@frasersoft.nospam.net> wrote in message
> You don't want the volume - that's the value of the 'volume control' > Look for MIXERCONTROL which defines xxx_CLASS_METER for different Audio > channels(Lines) and also mixerGetLineControls() which is used to get the > information. > (BTW I've never done this so I'm just searchng help) > Do look at www.torry.net as they have several controls for doing similar > things. I've seen audio metering components there - just can't remember > where :(
> HTH Pete
> "Mark Jacobs" <markjremovethisspuriousantispamst...@critical.co.uk> wrote in > message news:406a9fed@newsgroups.borland.com... > > I have looked, tried, tinkered and fretted. I do not know whether to open > waveIn or waveOut in order to > > monitor currently playing levels. I keep getting "An invalid flag was > passed to a system function." (code 10) > > from the following code :-
Not all Soundcards have PEAKMETERS (SoundBlasters and AC97's do NOT have them, and hence, cannot display a level meter on the standard Windows mixer control), so this rules out the methods discussed before. Is there a way to periodically read 4 bytes from each channel on the soundcard's output? It seems an absurdly simple thing to do, but the grief it has caused me so far is incredible!!! Surely, all I would need is the address of the primary sound buffer in order to read from it. I have the DirectSound header file and library, but I can't get the dang thing working for lack of documentation and examples. Has anyone got anything on DirectSound out there that isn't MSDN and has proper examples that work, and don't use the DirectSound8 interface, but use the one supplied with BCB5? -- Mark Jacobs DK Computing http://www.dkcomputing.co.uk ma...@criticalremovethisspuriousantispamstuff.co.uk
"Pete Fraser" <pete._no_spam_fra...@frasersoft.nospam.net> wrote in message
> You don't want the volume - that's the value of the 'volume control' > Look for MIXERCONTROL which defines xxx_CLASS_METER for different Audio > channels(Lines) and also mixerGetLineControls() which is used to get the > information. > (BTW I've never done this so I'm just searchng help) > Do look at www.torry.net as they have several controls for doing similar > things. I've seen audio metering components there - just can't remember > where :(
> HTH Pete
> "Mark Jacobs" <markjremovethisspuriousantispamst...@critical.co.uk> wrote in > message news:406a9fed@newsgroups.borland.com... > > I have looked, tried, tinkered and fretted. I do not know whether to open > waveIn or waveOut in order to > > monitor currently playing levels. I keep getting "An invalid flag was > passed to a system function." (code 10) > > from the following code :-
//------------------------------------------------------------------------- - void __fastcall TForm1::ProcessInput() { short *mybf=(short *)wvbfr; waveInStop(phwo); wh=waveInUnprepareHeader(phwo,&wvhd,sizeof(WAVEHDR)); if (wh!=MMSYSERR_NOERROR) return; zcDinMeter1->Value=(int)mybf[0]*100*zSlideBar1->Value/32768; zcDinMeter2->Value=(int)mybf[1]*100*zSlideBar1->Value/32768; zcMMTimer1->Enabled=true;
}
//------------------------------------------------------------------------- - /* Add a timer to the form. It should be set to an interval of 50ms or less to be useful, but 100ms seems to be adequate. I use Ziegler's Multimedia Timer so I can get good results from 20ms resolution. In the timer's OnTimer event, put the following :- */ //------------------------------------------------------------------------- - void __fastcall TForm1::zcMMTimer1Timer(TObject *Sender) { unsigned int vl; int mcierr,ii,jj; zcMMTimer1->Enabled=false; wvbfr[0]='\0'; wvbfr[1]='\0'; wvbfr[2]='\0'; wvbfr[3]='\0'; wvhd.lpData=wvbfr; wvhd.dwBufferLength=4; wvhd.dwLoops=0; wvhd.dwFlags=0; waveInStop(phwo); if (waveInPrepareHeader(phwo,&wvhd,sizeof(WAVEHDR))==MMSYSERR_NOERROR) { waveInAddBuffer(phwo,&wvhd,sizeof(WAVEHDR)); waveInStart(phwo); }
Hey presto, the values in ProcessInput()'s mybf buffer are :-
Left Channel = mybf[0] Right Channel=mybf[1]
with a range of -32767 to 32767 in each case.
I verified my results on a Soundblaster Live card. I have noticed that the Realtek AC97 Soundcard on another PC did not work properly. It could be indicative of faulty sound drivers. I'll try other PCs and report back. However, the code above has been arrived at painstakingly. Thankyou Microsoft! -- Mark Jacobs
"iim" <imamsiswa...@yahoo.com.sg> wrote in message
Not all Soundcards have PEAKMETERS (SoundBlasters and AC97's do NOT have them, and hence, cannot display a level meter on the standard Windows mixer control), so this rules out the methods discussed before. Is there a way to periodically read 4 bytes from each channel on the soundcard's output? It seems an absurdly simple thing to do, but the grief it has caused me so far is incredible!!! ...