mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 19:52:59 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
419
base/applications/sndrec32/audio_wavein.cpp
Normal file
419
base/applications/sndrec32/audio_wavein.cpp
Normal file
|
@ -0,0 +1,419 @@
|
|||
/* PROJECT: ReactOS sndrec32
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: base/applications/sndrec32/audio_wavein.cpp
|
||||
* PURPOSE: Sound recording
|
||||
* PROGRAMMERS: Marco Pagliaricci (irc: rendar)
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "audio_wavein.hpp"
|
||||
|
||||
_AUDIO_NAMESPACE_START_
|
||||
|
||||
void
|
||||
audio_wavein::init_(void)
|
||||
{
|
||||
ZeroMemory((LPVOID)&wave_format, sizeof(WAVEFORMATEX));
|
||||
wave_format.cbSize = sizeof(WAVEFORMATEX);
|
||||
wavein_handle = 0;
|
||||
recthread_id = 0;
|
||||
wakeup_recthread = 0;
|
||||
data_flushed_event = 0;
|
||||
buf_secs = _AUDIO_DEFAULT_WAVEINBUFSECS;
|
||||
status = WAVEIN_NOTREADY;
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::alloc_buffers_mem_(unsigned int buffs, float secs)
|
||||
{
|
||||
unsigned int onebuf_size = 0, tot_size = 0;
|
||||
|
||||
/* Release old memory */
|
||||
if (main_buffer)
|
||||
delete[] main_buffer;
|
||||
|
||||
if (wave_headers)
|
||||
delete[] wave_headers;
|
||||
|
||||
/* Calcs size of the buffers */
|
||||
onebuf_size = (unsigned int)((float)aud_info.byte_rate() * secs);
|
||||
tot_size = onebuf_size * buffs;
|
||||
|
||||
/* Allocs memory for the audio buffers */
|
||||
main_buffer = new BYTE[tot_size];
|
||||
/* Allocs memory for the `WAVEHDR' structures */
|
||||
wave_headers = (WAVEHDR *)new BYTE[sizeof(WAVEHDR) * buffs];
|
||||
/* Zeros memory */
|
||||
ZeroMemory(main_buffer, tot_size);
|
||||
ZeroMemory(wave_headers, sizeof(WAVEHDR) * buffs);
|
||||
/* Updates total size of the buffers */
|
||||
mb_size = tot_size;
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::free_buffers_mem_(void)
|
||||
{
|
||||
/* Frees memory */
|
||||
if (main_buffer)
|
||||
delete[] main_buffer;
|
||||
|
||||
|
||||
if (wave_headers)
|
||||
delete[] wave_headers;
|
||||
|
||||
main_buffer = 0;
|
||||
wave_headers = 0;
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::init_headers_(void)
|
||||
{
|
||||
/* If there is no memory for memory or headers, simply return */
|
||||
if ((!wave_headers) || (!main_buffer))
|
||||
return;
|
||||
|
||||
/* This is the size for one buffer */
|
||||
DWORD buf_sz = mb_size / buffers;
|
||||
/* This is the base address for one buffer */
|
||||
BYTE *buf_addr = main_buffer;
|
||||
/* Initializes headers */
|
||||
for (unsigned int i = 0; i < buffers; ++i)
|
||||
{
|
||||
wave_headers[i].dwBufferLength = mb_size / buffers;
|
||||
wave_headers[i].lpData = (LPSTR)buf_addr;
|
||||
buf_addr += buf_sz;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::prep_headers_(void)
|
||||
{
|
||||
MMRESULT err;
|
||||
bool error = false;
|
||||
|
||||
/* If there is no memory for memory or headers, throw error */
|
||||
if ((!wave_headers) || (!main_buffer) || (!wavein_handle))
|
||||
{
|
||||
/* TODO: throw error! */
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < buffers; ++i)
|
||||
{
|
||||
err = waveInPrepareHeader(wavein_handle, &wave_headers[i], sizeof(WAVEHDR));
|
||||
if (err != MMSYSERR_NOERROR)
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error)
|
||||
MessageBox(0, TEXT("waveInPrepareHeader Error."), 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::unprep_headers_(void)
|
||||
{
|
||||
MMRESULT err;
|
||||
bool error = false;
|
||||
|
||||
/* If there is no memory for memory or headers, throw error */
|
||||
if ((!wave_headers) || (!main_buffer) || (!wavein_handle))
|
||||
{
|
||||
/* TODO: throw error! */
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < buffers; ++i)
|
||||
{
|
||||
err = waveInUnprepareHeader(wavein_handle, &wave_headers[i], sizeof(WAVEHDR));
|
||||
if (err != MMSYSERR_NOERROR)
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error)
|
||||
MessageBox(0, TEXT("waveInUnPrepareHeader Error."), 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::add_buffers_to_driver_(void)
|
||||
{
|
||||
MMRESULT err;
|
||||
bool error = false;
|
||||
|
||||
/* If there is no memory for memory or headers, throw error */
|
||||
if ((!wave_headers) || (!main_buffer) || (!wavein_handle))
|
||||
{
|
||||
/* TODO: throw error! */
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < buffers; ++i)
|
||||
{
|
||||
err = waveInAddBuffer(wavein_handle, &wave_headers[i], sizeof(WAVEHDR));
|
||||
if (err != MMSYSERR_NOERROR)
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error)
|
||||
MessageBox(0, TEXT("waveInAddBuffer Error."), 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::close(void)
|
||||
{
|
||||
/* If wavein object is already in the status NOTREADY, nothing to do */
|
||||
if (status == WAVEIN_NOTREADY)
|
||||
return;
|
||||
|
||||
/* If the wavein is recording, then stop recording and close it */
|
||||
if (status == WAVEIN_RECORDING)
|
||||
stop_recording();
|
||||
|
||||
/* Updating status */
|
||||
status = WAVEIN_NOTREADY;
|
||||
|
||||
/* Waking up recording thread, so it can receive
|
||||
the `MM_WIM_CLOSE' message then dies */
|
||||
if (wakeup_recthread)
|
||||
SetEvent(wakeup_recthread);
|
||||
|
||||
/* Closing wavein stream */
|
||||
while ((waveInClose(wavein_handle)) != MMSYSERR_NOERROR)
|
||||
Sleep(1);
|
||||
|
||||
/* Release buffers memory */
|
||||
free_buffers_mem_();
|
||||
|
||||
/* Re-initialize variables to the initial state */
|
||||
init_();
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::open(void)
|
||||
{
|
||||
MMRESULT err;
|
||||
HANDLE recthread_handle = 0;
|
||||
|
||||
/* Checkin the status of the object */
|
||||
if (status != WAVEIN_NOTREADY)
|
||||
{
|
||||
/* TODO: throw error */
|
||||
}
|
||||
|
||||
/* Creating the EVENT object that will be signaled
|
||||
when the recording thread has to wake up */
|
||||
wakeup_recthread = CreateEvent(0, FALSE, FALSE, 0);
|
||||
|
||||
data_flushed_event = CreateEvent(0, FALSE, FALSE, 0);
|
||||
|
||||
if ((!wakeup_recthread) || (!data_flushed_event))
|
||||
{
|
||||
status = WAVEIN_ERR;
|
||||
MessageBox(0, TEXT("Thread Error."), 0, 0);
|
||||
/* TODO: throw error */
|
||||
}
|
||||
|
||||
/* Inialize buffers for recording audio data from the wavein audio line */
|
||||
alloc_buffers_mem_(buffers, buf_secs);
|
||||
init_headers_();
|
||||
|
||||
/* Sound format that will be captured by wavein */
|
||||
wave_format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wave_format.nChannels = aud_info.channels();
|
||||
wave_format.nSamplesPerSec = aud_info.sample_rate();
|
||||
wave_format.wBitsPerSample = aud_info.bits();
|
||||
wave_format.nBlockAlign = aud_info.block_align();
|
||||
wave_format.nAvgBytesPerSec = aud_info.byte_rate();
|
||||
|
||||
/* Creating the recording thread */
|
||||
recthread_handle = CreateThread(NULL,
|
||||
0,
|
||||
audio_wavein::recording_procedure,
|
||||
(PVOID)this,
|
||||
0,
|
||||
&recthread_id);
|
||||
/* Checking thread handle */
|
||||
if (!recthread_handle)
|
||||
{
|
||||
/* Updating status */
|
||||
status = WAVEIN_ERR;
|
||||
MessageBox(0, TEXT("Thread Error."), 0, 0);
|
||||
/* TODO: throw error */
|
||||
}
|
||||
|
||||
/* We don't need the thread handle anymore, so we can close it from now.
|
||||
(We'll just need the thread ID for the `waveInOpen' API) */
|
||||
CloseHandle(recthread_handle);
|
||||
|
||||
/* Opening audio line wavein */
|
||||
err = waveInOpen(&wavein_handle,
|
||||
0,
|
||||
&wave_format,
|
||||
recthread_id,
|
||||
0,
|
||||
CALLBACK_THREAD);
|
||||
|
||||
if (err != MMSYSERR_NOERROR)
|
||||
{
|
||||
/* Updating status */
|
||||
status = WAVEIN_ERR;
|
||||
|
||||
if (err == WAVERR_BADFORMAT)
|
||||
MessageBox(0, TEXT("waveInOpen Error"), 0, 0);
|
||||
|
||||
/* TODO: throw error */
|
||||
}
|
||||
|
||||
/* Update object status */
|
||||
status = WAVEIN_READY;
|
||||
|
||||
/* Now `audio_wavein' object is ready for audio recording! */
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::start_recording(void)
|
||||
{
|
||||
MMRESULT err;
|
||||
BOOL ev;
|
||||
|
||||
if ((status != WAVEIN_READY) && (status != WAVEIN_STOP))
|
||||
{
|
||||
/* TODO: throw error */
|
||||
}
|
||||
|
||||
/* Updating to the recording status */
|
||||
status = WAVEIN_RECORDING;
|
||||
|
||||
/* Let's prepare header of type WAVEHDR that we will pass to the driver
|
||||
with our audio informations, and buffer informations */
|
||||
prep_headers_();
|
||||
|
||||
/* The waveInAddBuffer function sends an input buffer to the given waveform-audio
|
||||
input device. When the buffer is filled, the application is notified. */
|
||||
add_buffers_to_driver_();
|
||||
|
||||
/* Signaling event for waking up the recorder thread */
|
||||
ev = SetEvent(wakeup_recthread);
|
||||
if (!ev)
|
||||
MessageBox(0, TEXT("Event Error."), 0, 0);
|
||||
|
||||
/* Start recording */
|
||||
err = waveInStart(wavein_handle);
|
||||
if (err != MMSYSERR_NOERROR)
|
||||
{
|
||||
/* Updating status */
|
||||
status = WAVEIN_ERR;
|
||||
MessageBox(0, TEXT("waveInStart Error."), 0, 0);
|
||||
/* TODO: throw error */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
audio_wavein::stop_recording(void)
|
||||
{
|
||||
MMRESULT err;
|
||||
|
||||
if (status != WAVEIN_RECORDING)
|
||||
return;
|
||||
|
||||
status = WAVEIN_FLUSHING;
|
||||
|
||||
/* waveInReset will make all pending buffer as done */
|
||||
err = waveInReset(wavein_handle);
|
||||
if ( err != MMSYSERR_NOERROR )
|
||||
{
|
||||
/* TODO: throw error */
|
||||
MessageBox(0, TEXT("waveInReset Error."), 0, 0);
|
||||
}
|
||||
|
||||
if (data_flushed_event)
|
||||
WaitForSingleObject(data_flushed_event, INFINITE);
|
||||
|
||||
/* Stop recording */
|
||||
err = waveInStop(wavein_handle);
|
||||
if (err != MMSYSERR_NOERROR)
|
||||
{
|
||||
/* TODO: throw error */
|
||||
MessageBox(0, TEXT("waveInStop Error."), 0, 0);
|
||||
}
|
||||
|
||||
/* The waveInUnprepareHeader function cleans up the preparation performed
|
||||
by the waveInPrepareHeader function */
|
||||
unprep_headers_();
|
||||
|
||||
status = WAVEIN_STOP;
|
||||
}
|
||||
|
||||
DWORD WINAPI
|
||||
audio_wavein::recording_procedure(LPVOID arg)
|
||||
{
|
||||
MSG msg;
|
||||
WAVEHDR *phdr;
|
||||
audio_wavein *_this = (audio_wavein *)arg;
|
||||
|
||||
/* Check the arg pointer */
|
||||
if (_this == 0)
|
||||
return 0;
|
||||
|
||||
/* The thread can go to sleep for now. It will be wake up only when
|
||||
there is audio data to be recorded */
|
||||
if (_this->wakeup_recthread)
|
||||
WaitForSingleObject(_this->wakeup_recthread, INFINITE);
|
||||
|
||||
/* If status of the `audio_wavein' object is not ready or recording the thread can exit */
|
||||
if ((_this->status != WAVEIN_READY) && (_this->status != WAVEIN_RECORDING))
|
||||
return 0;
|
||||
|
||||
/* Entering main polling loop */
|
||||
while (GetMessage(&msg, 0, 0, 0))
|
||||
{
|
||||
switch (msg.message)
|
||||
{
|
||||
case MM_WIM_DATA:
|
||||
phdr = (WAVEHDR *)msg.lParam;
|
||||
|
||||
if ((_this->status == WAVEIN_RECORDING) ||
|
||||
(_this->status == WAVEIN_FLUSHING))
|
||||
{
|
||||
if (phdr->dwFlags & WHDR_DONE)
|
||||
{
|
||||
/* Flushes recorded audio data to the `audio_receiver' object */
|
||||
_this->audio_rcvd.audio_receive((unsigned char *)phdr->lpData,
|
||||
phdr->dwBytesRecorded);
|
||||
|
||||
/* Updating `audio_receiver' total bytes received
|
||||
_AFTER_ calling `audio_receive' function */
|
||||
_this->audio_rcvd.bytes_received += phdr->dwBytesRecorded;
|
||||
}
|
||||
|
||||
/* If status is not flushing data, then we can re-add the buffer
|
||||
for reusing it. Otherwise, if we are flushing pending data,
|
||||
we cannot re-add buffer because we don't need it anymore */
|
||||
if (_this->status != WAVEIN_FLUSHING)
|
||||
{
|
||||
/* Let the audio driver reuse the buffer */
|
||||
waveInAddBuffer(_this->wavein_handle, phdr, sizeof(WAVEHDR));
|
||||
} else {
|
||||
/* If we are flushing pending data, we have to prepare
|
||||
to stop recording. Set WAVEHDR flag to 0, and fires
|
||||
the event `data_flushed_event', that will wake up
|
||||
the main thread that is sleeping into wavein_in::stop_recording()
|
||||
member function, waiting the last `MM_WIM_DATA' message
|
||||
that contain pending data */
|
||||
|
||||
phdr->dwFlags = 0;
|
||||
SetEvent(_this->data_flushed_event);
|
||||
|
||||
/* The recording is going to stop, so the recording thread can go to sleep! */
|
||||
WaitForSingleObject(_this->wakeup_recthread, INFINITE);
|
||||
}
|
||||
} /* if WAVEIN_RECORDING || WAVEIN_FLUSHING */
|
||||
break;
|
||||
|
||||
case MM_WIM_CLOSE:
|
||||
/* The thread can exit now */
|
||||
return 0;
|
||||
break;
|
||||
} /* end switch(msg.message) */
|
||||
} /* end while(GetMessage(...)) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_AUDIO_NAMESPACE_END_
|
Loading…
Add table
Add a link
Reference in a new issue