работа с микрофоном
помогите, плиз, не могу справиться. во-первых необходима одновременная работа в реалтайме с микрофоном (запись куда-то) и с наушниками (вывод звука). во-вторых, я не могу придумать, как бы писать с микрофона в память, а не в файл. то же самое с выводом звука, так как желательно выводить тоже из памяти. как хранить звук?
Есть несколько способов соответствующей организации буфера.
Приведу здесь исходник одного из них (класс на С++).
Вкратце объяснения: запись, обработку и воспроизведение надо реализовывать в разных потоках (во избежание потери данных и зависания программы). Ниже приведённый класс обеспечивает реализацию разделяемого между двумя потоками дека (т.е. двустороннего стека/очереди). Перед началом каких-либо действий с объектом CVector необходимо вызывать WaitForDuty(), по окончанию - LeaveDuty(). Дальше разбирайся сам, если будут вопросу - пиши.
Предупреждение: код далеко не в самом идеальном состоянии, но он рабочий (используется в реал-тайм системе распознавания речи) и достаточно быстрый.
#include <Windows.h>
const int nSizes=16;
const int pSizes[nSizes]={
0x1000,0x2000,0x4000,0x8000, /* 4K..32K */
0x10000,0x20000,0x40000,0x80000, /* 64K..512K */
0x100000,0x200000,0x400000,0x800000, /* 1M..8M */
0x1000000,0x2000000,0x4000000,0x8000000 /* 16M..128M */
};
const int nMinimalSize=4096;
template <typename T>
class CVector {
public:
CVector(): _nDesired(0) {
_pLast=_pFirst=_pBegin=new T [nMinimalSize];
_pEnd=_pBegin+nMinimalSize;
// init cs
InitializeCriticalSection(&_csAccess);
// init reach event
_hEvReach=CreateEvent(0,FALSE,FALSE,0);
}
~CVector() {
delete [] _pBegin;
// delete reach event
CloseHandle(_hEvReach);
// delete cs
DeleteCriticalSection(&_csAccess);
}
void WaitForDuty() {
EnterCriticalSection(&_csAccess);
}
void WaitForGtOrEq(int nDesired,bool bDuty=true) {
WaitForDuty();
if (size()<nDesired) {
_nDesired=nDesired;
LeaveDuty();
WaitForSingleObject(_hEvReach,INFINITE);
if (bDuty)
WaitForDuty();
}
else if (!bDuty)
LeaveDuty();
}
void SetDesired(int nDesired) {
_nDesired=nDesired;
}
bool IsReachDesired() const {
return WaitForSingleObject(_hEvReach,0)==WAIT_OBJECT_0;
}
void LeaveDuty() {
LeaveCriticalSection(&_csAccess);
}
T *begin() const {
return _pFirst;
}
T *end() const {
return _pLast;
}
int size() const {
return _pLast-_pFirst;
}
bool empty() const {
return size()==0;
}
T &operator[](int nPos) {
return *(_pFirst+nPos);
}
void back_insert(const T *pF,const T *pL) {
if (pL-pF<=_pEnd-_pLast) {
}
else if (_pLast-_pFirst+pL-pF<=_pEnd-_pBegin) {
MoveMemory(_pBegin,_pFirst,(_pLast-_pFirst)*sizeof(T));
int nShift=_pFirst-_pBegin;
_pFirst=_pBegin; _pLast-=nShift;
}
else {
int nDesired=_pLast-_pFirst+pL-pF;
int nActual=_pEnd-_pBegin;
while ((nActual<<=1)<nDesired);
T *pNew=new T [nActual];
CopyMemory(pNew,_pFirst,(_pLast-_pFirst)*sizeof(T));
int nSize=_pLast-_pFirst;
_pFirst=pNew; _pLast=_pFirst+nSize;
delete [] _pBegin;
_pEnd=(_pBegin=pNew)+nActual;
}
CopyMemory(_pLast,pF,(pL-pF)*sizeof(T));
_pLast+=pL-pF;
if (_nDesired!=0&&size()>=_nDesired) {
SetEvent(_hEvReach);
_nDesired=0;
}
}
void front_erase(int nS) {
_pFirst+=nS;
optimize_size();
}
void back_erase(int nS) {
_pLast-=nS;
optimize_size();
}
void clear() {
_pLast=_pFirst=_pBegin;
optimize_size();
}
private:
HANDLE _hEvReach;
int _nDesired;
CRITICAL_SECTION _csAccess;
void optimize_size() {
}
T *_pFirst;
T *_pLast;
T *_pBegin;
T *_pEnd;
};
Цитата:
Originally posted by Stas Kmet
помогите, плиз, не могу справиться. во-первых необходима одновременная работа в реалтайме с микрофоном (запись куда-то) и с наушниками (вывод звука). во-вторых, я не могу придумать, как бы писать с микрофона в память, а не в файл. то же самое с выводом звука, так как желательно выводить тоже из памяти. как хранить звук?
помогите, плиз, не могу справиться. во-первых необходима одновременная работа в реалтайме с микрофоном (запись куда-то) и с наушниками (вывод звука). во-вторых, я не могу придумать, как бы писать с микрофона в память, а не в файл. то же самое с выводом звука, так как желательно выводить тоже из памяти. как хранить звук?
То есть, если я правильно понял, ты хочешь в реал-тайме записывать звук в буфер, как-то его обрабатывать и выводить на колонки?
Немного не то. Моя задача - получать звук с микрофона и перекидывать его
по сетке, где он проигрывается. Эдакая система диспетчерской связи. На данном
этапе я реализовал запись с микрофона и кодирование в mp3, однако проблема в
том, что запись происходит не только с микрофона, а и с колонок. То есть
в файл пишется и то, что в данный момент играет в WinAMP'е. Это неприемлемо.
Я пробовал ковырять процедуру waveInOpen, вызов которой показан ниже, и один
из параметров у нее - deviceID. В хэлпе сказано, что этим идентификатором
должна быть константа WAVE_MAPPER. Другого я не нашел :(
Вот моя процедура инициализации рекордера:
Function TWaveRecorder.SetupRecord(P : PWaveRecorder) : Boolean;
Var
iErr: integer;
i: Integer;
begin
dwTotalwavesize := 0;
dwBytedatasize := 0;
bufindex := 0;
ProcessedBuffers := 0;
QueuedBuffers := 0;
{ открываем устройство для записи }
iErr := waveInOpen(@WaveIn, WAVE_MAPPER, pWaveFmtEx,
Integer(@BufferDoneCallBack),
Integer(P), CALLBACK_FUNCTION + WAVE_ALLOWSYNC );
If (iErr <> 0) Then
Begin
RecErrorMessage := 'Не могу открыть входное устройство для записи: ' + ^M +
TWaveInGetErrorText(iErr);
SetupRecord := FALSE;
Exit;
End;
{ сообщаем CloseWaveDeviceRecord(), что устройство открыто }
bDeviceOpen := TRUE;
{ подготавливаем заголовки }
InitWaveHeaders();
For i := 0 to fTotalBuffers-1 Do
Begin
iErr := waveInPrepareHeader( WaveIn, pWaveHeader, sizeof(TWAVEHDR));
If (iErr <> 0) Then
begin
CloseWaveDeviceRecord;
RecErrorMessage := 'Ошибка подготовки заголовка для записи: ' + ^M +
TWaveInGetErrorText(iErr);
SetupRecord := FALSE;
Exit;
end;
End;
{ добавляем первый буфер }
If (Not AddNextBuffer) Then
begin
SetupRecord := FALSE;
Exit;
end;
SetupRecord := TRUE;
end;
// а затем через нижеуказанную процедуру происходит кодирование и запись в MP3
procedure TWR.ProcessBuffer(uMsg : Word; P : Pointer; n : Integer; dwParam1: dword);
var
done: DWORD;
len: DWORD;
begin
inherited;
case umsg of
MM_WIM_OPEN:
begin
FillChar(BeConfig, SizeOf(BeConfig), #0);
BeConfig.Format.dwConfig:= BE_CONFIG_LAME;
with BeConfig.Format.LHV1 do
begin
dwStructSize:= sizeof(TLHV1);
bCopyright:= true;
dwReSampleRate:= 16000;
dwSampleRate:= 44100;
nMode:= BE_MP3_MODE_MONO;
dwBitrate:= 16;
end;
filelen:= 0;
PostMessage(MainWnd, wm_user+1, 0, filelen);
BeInitStream(BeConfig, NumSamples, Mp3BufSize, hLame);
GetMem(Mp3Buffer, Mp3BufSize);
hFile:= CreateFile('file.mp3', GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
end;
MM_WIM_CLOSE:
begin
beDeinitStream(hLame, mp3Buffer, dwWrite);
WriteFile(hFile, mp3buffer^, toWrite, dwWrite, nil);
filelen:= filelen + integer(dwWrite);
PostMessage(MainWnd, wm_user+1, 0, filelen);
beCloseStream(hLame);
FreeMem(Mp3Buffer);
CloseHandle(hFile);
end;
MM_WIM_DATA:
begin
done:= 0;
len:= pWAVEHDR(dwParam1).dwBytesRecorded;
while done < len do
begin
if (done + NumSamples * 2) < len
then toRead := NumSamples * 2
else toRead := len - done;
beEncodeChunk(hLame, toRead div 2, @pWAVEHDR(dwParam1).lpData[done], mp3Buffer, toWrite);
WriteFile(hFile, mp3buffer^, toWrite, dwWrite, nil);
filelen:= filelen + integer(dwWrite);
done := Done + ToRead;
end;
PostMessage(MainWnd, wm_user+1, 0, filelen);
end;
end;
end;
Есть несколько способов соответствующей организации буфера.
Приведу здесь исходник одного из них (класс на С++).
Честно говоря, я с C++ связываться не хочу, потому
что мои коллеги, как и я, не достигли в этом
языке необходимого уровня. Но все равно спасибо за ответ.
Stas Kmet наткнулся в поиске на вашу тему. Дело в том что сейчас занимаюсь данным вопросом в своей курсовой, а именно запись звука с микрофона и передача его по сети, за исключением того что дополнительно нужно реализовать тоже самое и с изображением... Я понимаю что уже много лет прошло, но если остались хоть какие-нибудь исходники Вашей программы буду очень благодарен за помощь. Всё что вижу написано на С++, а мне всё-таки Delphi ближе. Если что пишите на [email]webfriker@mail.ru[/email] буду очень признателен за любую помощь.
Предупреждение: код далеко не в самом идеальном состоянии, но он рабочий (используется в реал-тайм системе распознавания речи) и достаточно быстрый.