Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Record audio within a VFP application 1

Status
Not open for further replies.

awaresoft

Programmer
Feb 16, 2002
373
0
0
DE
I would like users to be able to record audio messages from within my VFP - ideally without having to shell out to another application.

Does anyone have any tips on how I can do this? I've searched these forums ("capture audio", "record audio"), Ed Leafe's Profox, and Steve Black's Wiki without success.

The closest I've found is an article on how to capture streaming video (without sound)

Anyone have any tips? Ideally I'm looking for a solution that uses native Windows API via Declare statements or a simple 3rd party DLL that does not require registration.

Thank you!
Malcolm
 
The MCI system allows simple recording of audio, like this:
Code:
xx=create('mciWaveFormAudil')
xx.RecordNew('C:\MyNewFile.wav')

  ** Have a "Stop" button on the form that will call:
  xx.Stop

* See this page for more about controlling MCI:
* [URL unfurl="true"]http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_command_strings.asp[/URL]

**************************************************
*-- Class:        mci (c:\source\winutil.vcx)
*-- Author:       William GC Steinford
*-- Time Stamp:   12/18/00 02:31:00 PM
*
DEFINE CLASS mci AS container


	Width = 236
	Height = 26
	Visible = .F.
	BackColor = RGB(0,128,128)
	*-- This stores the name of the MCI DeviceType this object is controlling
	device = "''"
	*-- Specifies the alias / ID used to refer to the MCI device that has been opened
	alias = "''"
	*-- This stores the file name (or other element name) that this MCI object is controlling
	element = "''"
	Name = "mci"


	ADD OBJECT lbltitle AS label WITH ;
		FontBold = .T., ;
		FontSize = 11, ;
		BackStyle = 0, ;
		Caption = "Media Control Interface (MCI)", ;
		Height = 17, ;
		Left = 8, ;
		Top = 3, ;
		Width = 220, ;
		ForeColor = RGB(192,192,192), ;
		Name = "lblTitle"


	PROCEDURE Init
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method Init
		*!*	#define mmsystem "WINMM.DLL" 
		DECLARE integer mciSendString IN WinMM.DLL ;
			   STRING cCommand, STRING @cRetStr, INTEGER nRetLen, ;
			   INTEGER wHnd
			   
		* Example Strings:
		*!* mciSendString("open cdaudio","",0,0) 
		*!*	=mciSendString("play cdaudio","",0,0) 
		*!*	=mciSendString("stop cdaudio","",0,0) 
		*!*	=mciSendString("set cdaudio door open","",0,0) 


		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method Init
	ENDPROC


	*-- Close() -- closes the currently open MCI device ID/Alias
	PROCEDURE close
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method close
		THIS.SendString( "close "+THIS.Alias )

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method close
	ENDPROC


	*-- Delete( cOptions )  -- If no options are specified, then deletes from here to the end.
	PROCEDURE delete
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method delete
		LPARAMETERS pcOpt
		THIS.SendString( "delete "+THIS.Alias+' '+iif(VarType(pcOpt)='C',pcOpt,'') )

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method delete
	ENDPROC


	*-- Open( cMCIType [, cAlias [, cFileName ]] )
	PROCEDURE open
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method open
		LPARAMETER lcDevice, lcAlias, lcElement
		THIS.Device   = lcDevice
		THIS.Alias    = iif( type('lcAlias')='C',   lcAlias,   lcDevice )
		THIS.Element  = iif( type('lcElement')='C', lcElement, ''       )
		THIS.SendString( "open "+THIS.Element+" type "+THIS.Device+" alias "+THIS.Alias)

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method open
	ENDPROC


	*-- Pause()
	PROCEDURE pause
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method pause
		THIS.SendString( 'pause '+THIS.alias )
		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method pause
	ENDPROC


	*-- Play( [cOptions] )
	PROCEDURE play
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method play
		LPARAMETERS pcOptions
		THIS.SendString( "play "+THIS.Alias+' '+iif(VarType(pcOptions)='C',pcOptions,'') )

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method play
	ENDPROC


	*-- Record( cOptions )
	PROCEDURE record
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method record
		LPARAMETERS pcOptions
		THIS.SendString( "record "+THIS.Alias+' '+iif(Vartype(pcOptions)='C',pcOptions,'') )

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method record
	ENDPROC


	*-- Save( cFileName )
	PROCEDURE save
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method save
		LPARAMETER pcFileName
		if VarType(pcFileName)='C'
		  THIS.SendString( 'save '+this.alias+' '+pcFileName )
		else
		  if lower(THIS.Element)<>'new'
		    THIS.SendString( 'save '+this.alias )
		  endif
		endif

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method save
	ENDPROC


	*-- Seek( cLocation ) -- set the position to start from.  can be: "end", "start", or a numbered position (according to the current SET TIME FORMAT (bytes/milliseconds/samples/etc.)
	PROCEDURE seek
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method seek
		LPARAMETERS pcLocation
		THIS.SendString( 'seek '+this.Alias+' to '+pcLocation )
		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method seek
	ENDPROC


	*-- mciSendString( cString, @cReturn, nRetLen, wHnd )
	PROCEDURE sendstring
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method sendstring
		LPARAMETERS cString
		LOCAL cRet, err
		cRet = space(60)
		err = mciSendString(cString,@cRet,60,0) 

		return cRet


		** Modify Class mci of [c:\source\WINUTIL.VCX] Method sendstring
	ENDPROC


	*-- Set( cSetItem ) -- Use this to set the control settings for the device.
	PROCEDURE set
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method set
		LPARAMETERS cStat
		RETURN THIS.SendString( 'set '+THIS.Alias+' '+cStat )

		*  These are all the valid 'Set' commands for each kind of device
		*!*	cdaudio 
		*!*	 audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off
		*!*	audio right on 
		*!*	door closed
		*!*	door open
		*!*	time format milliseconds
		*!*	time format msf
		*!*	time format tmsf 
		*!*	 
		*!*	digitalvideo 
		*!*	 audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off
		*!*	audio right on
		*!*	door closed
		*!*	door open 
		*!*	 file format format
		*!*	seek exactly on
		*!*	seek exactly off
		*!*	speed factor
		*!*	still file format format
		*!*	time format frames
		*!*	time format milliseconds
		*!*	video off
		*!*	video on 
		*!*	 
		*!*	overlay 
		*!*	 audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off 
		*!*	 audio right on
		*!*	door closed
		*!*	door open
		*!*	video off
		*!*	video on 
		*!*	 
		*!*	sequencer 
		*!*	 audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off
		*!*	audio right on
		*!*	door closed
		*!*	door open
		*!*	master MIDI
		*!*	master none
		*!*	master SMPTE
		*!*	offset time 
		*!*	 port mapper
		*!*	port none
		*!*	port port_number
		*!*	slave file
		*!*	slave MIDI
		*!*	slave none
		*!*	slave SMPTE
		*!*	tempo tempo_value
		*!*	time format milliseconds
		*!*	time format SMPTE fps
		*!*	time format SMPTE 30 drop
		*!*	time format song pointer 
		*!*	 
		*!*	vcr 
		*!*	 assemble record on
		*!*	assemble record off
		*!*	audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off
		*!*	audio right on
		*!*	clock time
		*!*	counter format
		*!*	counter value
		*!*	door closed
		*!*	door open
		*!*	index counter
		*!*	index date
		*!*	index time
		*!*	index timecode
		*!*	length duration
		*!*	pause timeout
		*!*	postroll duration -
		*!*	duration 
		*!*	 power on
		*!*	power off
		*!*	preroll duration duration
		*!*	record format SP
		*!*	record format LP
		*!*	record format EP
		*!*	speed factor
		*!*	time format frames
		*!*	time format hms
		*!*	time format milliseconds
		*!*	time format msf
		*!*	time format SMPTE fps
		*!*	time format SMPTE 30 drop
		*!*	time format tmsf
		*!*	time mode counter
		*!*	time mode detect
		*!*	time mode timecode
		*!*	tracking plus
		*!*	tracking minus
		*!*	tracking reset 
		*!*	 
		*!*	videodisc 
		*!*	 audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off
		*!*	audio right on
		*!*	door closed 
		*!*	 door open
		*!*	time format frames
		*!*	time format hms
		*!*	time format milliseconds
		*!*	time format track
		*!*	video off
		*!*	video on 
		*!*	 
		*!*	waveaudio 
		*!* alignment <integer>
		*!*	any input
		*!*	any output
		*!*	audio all off
		*!*	audio all on
		*!*	audio left off
		*!*	audio left on
		*!*	audio right off
		*!*	audio right on
		*!*	bitspersample <bit_count>
		*!*	bytespersec <byte_rate> 
		*!* channels <channel_count>
		*!*	door closed
		*!*	door open
		*!*	format tag pcm
		*!*	format tag tag
		*!*	input integer
		*!*	output integer
		*!*	samplespersec <integer>
		*!*	time format bytes
		*!*	time format milliseconds
		*!*	time format samples 
		*!*	 

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method set
	ENDPROC


	PROCEDURE stop
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method stop
		THIS.SendString( "stop "+THIS.Device )

		Return .t.
		** Modify Class mci of [c:\source\WINUTIL.VCX] Method stop
	ENDPROC


ENDDEFINE
*
*-- EndDefine: mci
**************************************************

**************************************************
*-- Class:        mciwaveformaudio (c:\source\winutil.vcx)
*-- ParentClass:  mci (c:\source\winutil.vcx)
*-- BaseClass:    container
*-- Time Stamp:   12/18/00 12:24:11 PM
*
DEFINE CLASS mciwaveformaudio AS mci


	Name = "mciwaveformaudio"
	lblTitle.Alignment = 2
	lblTitle.Caption = "MCI WaveForm Audio"
	lblTitle.Name = "lblTitle"


	PROCEDURE recordnew
		** Modify Class mciwaveformaudio of [c:\source\WINUTIL.VCX] Method recordnew
		LPARAMETER pcFName
		if not empty(THIS.Device)
		  THIS.SendString('close '+this.device)
		endif
		THIS.Device = 'mywaveaudio'
		THIS.SendString('open new type waveaudio alias '+THIS.Device+' buffer 6')
		THIS.SendString('record '+This.Device)

		Return .t.
		** Modify Class mciwaveformaudio of [c:\source\WINUTIL.VCX] Method recordnew
	ENDPROC


ENDDEFINE
*
*-- EndDefine: mciwaveformaudio
**************************************************

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Wgcs!

Wow! That's exactly what I'm looking for. Thank you very much!

For others following this thread, I also came across the following:

This class is able to record audio input from playback devices like Wave, Microphone, etc.

Note that the News2News solution requires an active membership ($30-$80) to access this example. News2News is a worthwhile service.

Malcolm
 
Oh, I'm sorry, I didn't read it carefully enough... that page is just showing how to use the class featured on the member's only page.

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Bill,

I'm trying to get your posted code to work and seem to be having some difficulty. I'm not getting any errors - but I'm not generating a saved file as well.

I'm using the following scaffolding to test your class. Am I missing something obvious? (And, yes, I can record audio fine with Sound Recorder - just verified :)

Thank you very much for your help!
Malcolm

Code:
oForm = CreateObject("clsForm")
oForm.Show()
Read Events
Return

define class clsForm as Form

	* NOTE: class ends in "Audio" vs "Audil"
	add object mciRecorder as mciWaveFormAudio
	add object cmdRecord   as CommandButton with caption = "Record"
	add object cmdStop     as CommandButton with caption = "Stop"

	function Init()
		with ThisForm
			.Move( 0, 0, 300, 100 )
			.AutoCenter = .T.
			.mciRecorder.Visible = .T.
			.cmdRecord.Move( 5, 50, 50, 25 )
			.cmdStop.Move( 65, 50, 50, 25 )
		endwith
	endfunc
	
	function cmdRecord.Click()
		wait window nowait "Recording ..."
		ThisForm.mciRecorder.RecordNew('C:\MyNewFile.wav')
	endfunc
	
	function cmdStop.Click()
		wait window nowait "Stopped recording ..."
		ThisForm.mciRecorder.Stop()
	endfunc
	
	function Destroy()
		clear events
	endfunc
enddefine
 
Sorry, I guess I hadn't tested the code since I had first written it... it also needs you to call the MCI.save(filename) command.
That is, your "stop" button function should be:
Code:
 function cmdStop.Click()
        wait window nowait "Stopped recording ..."
        ThisForm.mciRecorder.Stop()
        ThisForm.mciRecorder.Save('C:\MyNewFile.wav')
    endfunc

Since we were using exceletel, we went with the exceletel wav recording tools, and I never finished polishing up this class.... if you look at my code, the filename passed to RecordNew is never used; I meant to save it and store it there when the stop method is called.

You'll also notice that there is no error checking, so mci can easily get into a bad state where no more recording will happen.

But, I just tested the code below, and it does work, though you'll have to determine how to back-feed it into the class (I just did this at the command prompt):
Code:
DECLARE integer mciSendString IN WinMM.DLL ;
   STRING cCommand, STRING @cRetStr, INTEGER nRetLen, ;
   INTEGER wHnd
* declare return string:
retstr=space(100)
retlen=100
* In case "mywaveaudio" is still open
?mciSendString( 'close mywaveaudio ', @retstr, @retlen, _screen.HWnd )
?mciSendString( 'open new type waveaudio alias mywaveaudio buffer 6', @retstr, @retlen, _screen.HWnd )
?mciSendString( 'record mywaveaudio', @retstr, @retlen, _screen.HWnd )
?mciSendString( 'stop mywaveaudio', @retstr, @retlen, _screen.HWnd )
?mciSendString( 'save mywaveaudio c:\temp\rec.wav', @retstr, @retlen, _screen.HWnd )
Note that the return value (displayed on the desktop) should be 0 if successful, or something > 256 if it fails (since MCIERR_BASE is 256). Here are the errors it may return:
Code:
/* MCI error return values */
#define MCIERR_INVALID_DEVICE_ID        (MCIERR_BASE + 1)
#define MCIERR_UNRECOGNIZED_KEYWORD     (MCIERR_BASE + 3)
#define MCIERR_UNRECOGNIZED_COMMAND     (MCIERR_BASE + 5)
#define MCIERR_HARDWARE                 (MCIERR_BASE + 6)
#define MCIERR_INVALID_DEVICE_NAME      (MCIERR_BASE + 7)
#define MCIERR_OUT_OF_MEMORY            (MCIERR_BASE + 8)
#define MCIERR_DEVICE_OPEN              (MCIERR_BASE + 9)
#define MCIERR_CANNOT_LOAD_DRIVER       (MCIERR_BASE + 10)
#define MCIERR_MISSING_COMMAND_STRING   (MCIERR_BASE + 11)
#define MCIERR_PARAM_OVERFLOW           (MCIERR_BASE + 12)
#define MCIERR_MISSING_STRING_ARGUMENT  (MCIERR_BASE + 13)
#define MCIERR_BAD_INTEGER              (MCIERR_BASE + 14)
#define MCIERR_PARSER_INTERNAL          (MCIERR_BASE + 15)
#define MCIERR_DRIVER_INTERNAL          (MCIERR_BASE + 16)
#define MCIERR_MISSING_PARAMETER        (MCIERR_BASE + 17)
#define MCIERR_UNSUPPORTED_FUNCTION     (MCIERR_BASE + 18)
#define MCIERR_FILE_NOT_FOUND           (MCIERR_BASE + 19)
#define MCIERR_DEVICE_NOT_READY         (MCIERR_BASE + 20)
#define MCIERR_INTERNAL                 (MCIERR_BASE + 21)
#define MCIERR_DRIVER                   (MCIERR_BASE + 22)
#define MCIERR_CANNOT_USE_ALL           (MCIERR_BASE + 23)
#define MCIERR_MULTIPLE                 (MCIERR_BASE + 24)
#define MCIERR_EXTENSION_NOT_FOUND      (MCIERR_BASE + 25)
#define MCIERR_OUTOFRANGE               (MCIERR_BASE + 26)
#define MCIERR_FLAGS_NOT_COMPATIBLE     (MCIERR_BASE + 28)
#define MCIERR_FILE_NOT_SAVED           (MCIERR_BASE + 30)
#define MCIERR_DEVICE_TYPE_REQUIRED     (MCIERR_BASE + 31)
#define MCIERR_DEVICE_LOCKED            (MCIERR_BASE + 32)
#define MCIERR_DUPLICATE_ALIAS          (MCIERR_BASE + 33)
#define MCIERR_BAD_CONSTANT             (MCIERR_BASE + 34)
#define MCIERR_MUST_USE_SHAREABLE       (MCIERR_BASE + 35)
#define MCIERR_MISSING_DEVICE_NAME      (MCIERR_BASE + 36)
#define MCIERR_BAD_TIME_FORMAT          (MCIERR_BASE + 37)
#define MCIERR_NO_CLOSING_QUOTE         (MCIERR_BASE + 38)
#define MCIERR_DUPLICATE_FLAGS          (MCIERR_BASE + 39)
#define MCIERR_INVALID_FILE             (MCIERR_BASE + 40)
#define MCIERR_NULL_PARAMETER_BLOCK     (MCIERR_BASE + 41)
#define MCIERR_UNNAMED_RESOURCE         (MCIERR_BASE + 42)
#define MCIERR_NEW_REQUIRES_ALIAS       (MCIERR_BASE + 43)
#define MCIERR_NOTIFY_ON_AUTO_OPEN      (MCIERR_BASE + 44)
#define MCIERR_NO_ELEMENT_ALLOWED       (MCIERR_BASE + 45)
#define MCIERR_NONAPPLICABLE_FUNCTION   (MCIERR_BASE + 46)
#define MCIERR_ILLEGAL_FOR_AUTO_OPEN    (MCIERR_BASE + 47)
#define MCIERR_FILENAME_REQUIRED        (MCIERR_BASE + 48)
#define MCIERR_EXTRA_CHARACTERS         (MCIERR_BASE + 49)
#define MCIERR_DEVICE_NOT_INSTALLED     (MCIERR_BASE + 50)
#define MCIERR_GET_CD                   (MCIERR_BASE + 51)
#define MCIERR_SET_CD                   (MCIERR_BASE + 52)
#define MCIERR_SET_DRIVE                (MCIERR_BASE + 53)
#define MCIERR_DEVICE_LENGTH            (MCIERR_BASE + 54)
#define MCIERR_DEVICE_ORD_LENGTH        (MCIERR_BASE + 55)
#define MCIERR_NO_INTEGER               (MCIERR_BASE + 56)

#define MCIERR_WAVE_OUTPUTSINUSE        (MCIERR_BASE + 64)
#define MCIERR_WAVE_SETOUTPUTINUSE      (MCIERR_BASE + 65)
#define MCIERR_WAVE_INPUTSINUSE         (MCIERR_BASE + 66)
#define MCIERR_WAVE_SETINPUTINUSE       (MCIERR_BASE + 67)
#define MCIERR_WAVE_OUTPUTUNSPECIFIED   (MCIERR_BASE + 68)
#define MCIERR_WAVE_INPUTUNSPECIFIED    (MCIERR_BASE + 69)
#define MCIERR_WAVE_OUTPUTSUNSUITABLE   (MCIERR_BASE + 70)
#define MCIERR_WAVE_SETOUTPUTUNSUITABLE (MCIERR_BASE + 71)
#define MCIERR_WAVE_INPUTSUNSUITABLE    (MCIERR_BASE + 72)
#define MCIERR_WAVE_SETINPUTUNSUITABLE  (MCIERR_BASE + 73)

#define MCIERR_SEQ_DIV_INCOMPATIBLE     (MCIERR_BASE + 80)
#define MCIERR_SEQ_PORT_INUSE           (MCIERR_BASE + 81)
#define MCIERR_SEQ_PORT_NONEXISTENT     (MCIERR_BASE + 82)
#define MCIERR_SEQ_PORT_MAPNODEVICE     (MCIERR_BASE + 83)
#define MCIERR_SEQ_PORT_MISCERROR       (MCIERR_BASE + 84)
#define MCIERR_SEQ_TIMER                (MCIERR_BASE + 85)
#define MCIERR_SEQ_PORTUNSPECIFIED      (MCIERR_BASE + 86)
#define MCIERR_SEQ_NOMIDIPRESENT        (MCIERR_BASE + 87)

#define MCIERR_NO_WINDOW                (MCIERR_BASE + 90)
#define MCIERR_CREATEWINDOW             (MCIERR_BASE + 91)
#define MCIERR_FILE_READ                (MCIERR_BASE + 92)
#define MCIERR_FILE_WRITE               (MCIERR_BASE + 93)

#define MCIERR_NO_IDENTITY              (MCIERR_BASE + 94)

For more info on MCI, see:
-- has some example code
-- The "open" command syntax
-- the "save" command syntax


- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Bill,

Thank you very much for taking the time to help me out. I followed your explanation, code, and related documentation and now have something that works.

Best regards,
Malcolm
 
I'm glad you got it working!

- Bill

Get the best answers to your questions -- See FAQ481-4875.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top