class EL_AUDIO_INPUT_DEVICE

(source code)

description

Streams audio from microphone

note
	description: "Streams audio from microphone"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2022-11-15 19:56:06 GMT (Tuesday 15th November 2022)"
	revision: "5"

class
	EL_AUDIO_INPUT_DEVICE

inherit
	EL_MULTIMEDIA_SYSTEM_C_API
		export
			{NONE} all
		undefine
			io
		end

	EL_MODULE_LIO

create
	make

feature {NONE} -- Initialization

	make (a_waveform_format: EL_WAVEFORM_FORMAT; clip_duration_millisecs: INTEGER)
			--
		local
			i: INTEGER
		do
			waveform_format := a_waveform_format
			create wave_in_handle.make
			create audio_buffers.make
			from i := 1 until i > Num_audio_buffers loop
				audio_buffers.extend (
					create {EL_WAVE_AUDIO_16_BIT_CLIP}.make (waveform_format, clip_duration_millisecs)
				)
				i := i + 1
			end
		end

feature -- Element change

	set_win_handle (a_win_handle: POINTER)
			--
		do
			win_handle := a_win_handle
		end

feature -- Access

	is_win_handle_valid: BOOLEAN
			--
		do
			Result := is_attached (win_handle)
		end

feature -- Basic operations

	open: INTEGER
			--
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := c_wave_in_open (
				wave_in_handle.item,
				Wave_mapper,
				waveform_format.item,
				win_handle,
				Default_pointer,
				Callback_window
			)
		end

	prepare_headers: INTEGER
			--
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := MM_sys_err_noerror
			from
				audio_buffers.start
			until
				audio_buffers.off or Result /= MM_sys_err_noerror
			loop
				Result := c_wave_in_prepare_header (
					wave_in_handle.item,
					audio_buffers.item.item,
					audio_buffers.first.structure_size
				)
				audio_buffers.forth
			end
		end

	add_buffers: INTEGER
			-- Add buffers for the audio device to fill with audio data
			-- More than one is required in case it is not possible to return it quickly enough to the driver
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := MM_sys_err_noerror
			from
				audio_buffers.start
			until
				audio_buffers.off or Result /= MM_sys_err_noerror
			loop
				Result := c_wave_in_add_buffer (
					wave_in_handle.item,
					audio_buffers.item.item,
					audio_buffers.first.structure_size
				)
				audio_buffers.forth
			end
		end

	requeue_buffer (audio_buffer: POINTER): INTEGER
			-- Requeue this buffer so the driver can use it for another block of audio
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := c_wave_in_add_buffer (
				wave_in_handle.item,
				audio_buffer,
				audio_buffers.first.structure_size
			)
		end

	start: INTEGER
			--
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := c_wave_in_start (wave_in_handle.item)
		end

	reset: INTEGER
			--
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := c_wave_in_reset (wave_in_handle.item)
		end

	close: INTEGER
			--
		require
			valid_win_handle: is_win_handle_valid
		do
			Result := c_wave_in_close (wave_in_handle.item)
			win_handle := Default_pointer
		end

feature {NONE} -- Implementation

	wave_in_handle: EL_WAVE_IN_HANDLE

	waveform_format: EL_WAVEFORM_FORMAT

	audio_buffers: LINKED_LIST [EL_WAVE_AUDIO_16_BIT_CLIP]

	win_handle: POINTER

	Num_audio_buffers: INTEGER = 3

feature {NONE} -- Externals

	c_wave_in_open (
			-- Pointer to a buffer that receives a handle identifying the open waveform-audio input device.
		hwi: POINTER;

			-- Identifier of the waveform-audio input device to open.
		device_id: INTEGER;

			-- Pointer to a WAVEFORMATEX structure that identifies the desired format
			-- for recording waveform-audio data.
		pwfx: POINTER

			-- Pointer to a fixed callback function, an event handle, a handle to a window
		dwCallback: POINTER

			-- User-instance data passed to the callback mechanism.
		dwCallbackInstance: POINTER;

			-- Flags for opening the device.
		flags: INTEGER

	): INTEGER
			-- Opens the given waveform-audio input device for recording

			--| waveInOpen( OUT LPHWAVEIN phwi, IN UINT uDeviceID,
		    --|				IN LPCWAVEFORMATEX pwfx, IN DWORD_PTR dwCallback,
		    --|				IN DWORD_PTR dwCallbackInstance, IN DWORD fdwOpen)
		external
			"C [macro <mmsystem.h>] (LPHWAVEIN, UINT, LPCWAVEFORMATEX, DWORD_PTR, DWORD_PTR, DWORD): EIF_INTEGER"
		alias
			"waveInOpen"
		end

	c_wave_in_prepare_header (
		phwin: POINTER;
			-- handle identifying the open waveform-audio input device

		wave_header: POINTER;
			-- Pointer to WAVEHDR struct

		size: INTEGER
			-- Size of WAVEHDR struct
	): INTEGER
			-- MMRESULT waveInPrepareHeader(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
		external
			"C inline use <mmsystem.h>"
		alias
			"waveInPrepareHeader  (*(LPHWAVEIN) $phwin, (LPWAVEHDR) $wave_header, (UINT) $size)"
		end

	c_wave_in_add_buffer (
		phwin: POINTER;
			-- handle identifying the open waveform-audio input device

		wave_header: POINTER;
			-- Pointer to WAVEHDR struct

		size: INTEGER
			-- Size of WAVEHDR struct
	): INTEGER
			-- MMRESULT waveInAddBuffer(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
		external
			"C inline use <mmsystem.h>"
		alias
			"waveInAddBuffer (*(LPHWAVEIN) $phwin, (LPWAVEHDR) $wave_header, (UINT) $size)"
		end

	c_wave_in_start (
		phwin: POINTER
			-- handle identifying the open waveform-audio input device
	): INTEGER
			-- MMRESULT waveInStart (HWAVEIN hwi)
		external
			"C inline use <mmsystem.h>"
		alias
			"waveInStart (*(LPHWAVEIN) $phwin)"
		end

	c_wave_in_reset (
		phwin: POINTER
			-- handle identifying the open waveform-audio input device
	): INTEGER
			-- Stops input on the given waveform-audio input device and resets the current position to zero.
			-- All pending buffers are marked as done and returned to the application.

			--| MMRESULT waveInStart(HWAVEIN hwi)
		external
			"C inline use <mmsystem.h>"
		alias
			"waveInReset (*(LPHWAVEIN) $phwin)"
		end

	c_wave_in_close (
		phwin: POINTER
			-- handle identifying the open waveform-audio input device
	): INTEGER
			-- closes the given waveform-audio input device

			--| MMRESULT waveInStart(HWAVEIN hwi)
		external
			"C inline use <mmsystem.h>"
		alias
			"waveInClose (*(LPHWAVEIN) $phwin)"
		end

invariant

	valid_wave_in_handle: wave_in_handle /= Void
	valid_audio_clip: audio_buffers /= Void
	valid_audio_buffer_structure_size: audio_buffers.first.structure_size /= 0

end