Source file: /~heha/hs/AudioPipe.zip/src/AudioPipe.c

#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <mmsystem.h>
#define elemof(x) (sizeof(x)/sizeof(*(x)))
typedef enum {false, true} bool;
#undef RtlFillMemory
void WINAPI RtlFillMemory(PVOID,SIZE_T,BYTE);

UINT InNum, InList[4];
UINT OutNum, OutList[4];

_declspec(naked) DWORD* _fastcall ScanMemD(DWORD ecx, DWORD* edx, DWORD eax) {_asm{
	jecxz	e0
	mov	eax,[esp+4]
	xchg	edi,edx
	repne	scasd
	xchg	edx,edi
	lea	eax,[edx-4]
	je	e1
e0:	xor	eax,eax
e1:	ret	4
}}

void FillInputDevices(HWND hList) {
 int i,j;
 WAVEINCAPS wic;

 ListBox_ResetContent(hList);		// empty list
 j=waveInGetNumDevs();
 for (i=0; i<j; i++) {
  waveInGetDevCaps(i,&wic,sizeof(wic));
  ListBox_AddString(hList,wic.szPname);
  if (ScanMemD(InNum,InList,i)) ListBox_SetSel(hList,TRUE,i);
 }
}

void FillOutputDevices(HWND hList) {
 int i,j;
 WAVEOUTCAPS woc;

 ListBox_ResetContent(hList);		// empty list
 j=waveOutGetNumDevs();
 for (i=0; i<j; i++) {
  waveOutGetDevCaps(i,&woc,sizeof(woc));
  ListBox_AddString(hList,woc.szPname);
  if (ScanMemD(OutNum,OutList,i)) ListBox_SetSel(hList,TRUE,i);
 }
}

void MakeWaveFormat(UINT Channels, DWORD SampleRate, UINT Bits, PWAVEFORMATEX wfe) {
 wfe->wFormatTag	= WAVE_FORMAT_PCM;
 wfe->nChannels		= Channels;
 wfe->nSamplesPerSec	= SampleRate;
 wfe->nAvgBytesPerSec	= SampleRate *
(wfe->nBlockAlign	= ((Bits+7)>>3) * Channels);
 wfe->wBitsPerSample	= Bits;
 wfe->cbSize		= 0;
}

bool CheckExtraFormat(UINT Channels, DWORD SampleRate, UINT Bits,
  UINT DeviceId, bool OutFunc) {
 WAVEFORMATEX wfe;
 MMRESULT r;
 MakeWaveFormat(Channels,SampleRate,Bits,&wfe);
 if (OutFunc) r=waveOutOpen(NULL,DeviceId,&wfe,0,0,WAVE_FORMAT_QUERY);
 else r=waveInOpen(NULL,DeviceId,&wfe,0,0,WAVE_FORMAT_QUERY);
 if (r!=WAVERR_BADFORMAT) return true;
 return false;
}

DWORD CheckExtraFormats(UINT DeviceId, bool OutFunc) {
 UINT Channels;
 UINT Bits;
 static const DWORD SampleRates[]={44100,48000,96000,192000};
 UINT SR_Index;
 DWORD mask=1, ret=0;

 for (Channels=2; Channels<=6; Channels+=2) {			// 3*
  for (SR_Index=0; SR_Index<elemof(SampleRates); SR_Index++) {	// 4*
   for (Bits=16; Bits<=24; Bits+=8) {				// 2 = 24 combinations
    if (CheckExtraFormat(Channels,SampleRates[SR_Index],Bits,DeviceId,OutFunc)) ret|=mask;
    mask<<=1;
   }
  }
 }
 return ret;
}

void FillWaveformCharacteristics(HWND Dlg) {
 union {
  WAVEINCAPS wic;
  WAVEOUTCAPS woc;
 }caps;
 DWORD CommonStandardFormats=(DWORD)-1;	// all bits ON
 DWORD CommonExtraFormats=(DWORD)-1;	// all bits ON
 UINT i;
 HWND w;
 TCHAR buf[32];

 for (i=0; i<InNum; i++) {
  waveInGetDevCaps(InList[i],&caps.wic,sizeof(caps.wic));
  CommonStandardFormats &= caps.wic.dwFormats;
  CommonExtraFormats &= CheckExtraFormats(InList[i],false);
 }
 for (i=0; i<OutNum; i++) {
  waveOutGetDevCaps(OutList[i],&caps.woc,sizeof(caps.woc));
  CommonStandardFormats &= caps.woc.dwFormats;
  CommonExtraFormats &= CheckExtraFormats(OutList[i],true);
 }
// now we have all common capabilities, fill the combo boxes with defaults
 w=GetDlgItem(Dlg,16);		// "Number of channels"
 GetWindowText(w,buf,elemof(buf));
 ComboBox_ResetContent(w);
 if (CommonStandardFormats &	(WAVE_FORMAT_1M08|WAVE_FORMAT_1M16
				|WAVE_FORMAT_2M08|WAVE_FORMAT_2M16
				|WAVE_FORMAT_4M08|WAVE_FORMAT_4M16))
   ComboBox_AddString(w,"1 (mono)");
 if (CommonStandardFormats &	(WAVE_FORMAT_1S08|WAVE_FORMAT_1S16
				|WAVE_FORMAT_2S08|WAVE_FORMAT_2S16
				|WAVE_FORMAT_4S08|WAVE_FORMAT_4S16))
   ComboBox_AddString(w,"2 (stereo)");
 if (CommonExtraFormats & 0x0000FF00)	// any format with 4 channels
   ComboBox_AddString(w,"4 (quadro)");
 if (CommonExtraFormats & 0x00FF0000)	// any format with 6 channels
   ComboBox_AddString(w,"6 (5.1)");
 if (!buf[0]) ComboBox_GetLBText(w,ComboBox_GetCount(w)-1,buf);
 SetWindowText(w,buf);

 w=GetDlgItem(Dlg,17);		// "Sample rate [Sa/s]"
 GetWindowText(w,buf,elemof(buf));
 ComboBox_ResetContent(w);
 if (CommonStandardFormats &	(WAVE_FORMAT_1M08|WAVE_FORMAT_1M16
				|WAVE_FORMAT_1S08|WAVE_FORMAT_1S16))
   ComboBox_AddString(w,"11025");
 if (CommonStandardFormats &	(WAVE_FORMAT_2M08|WAVE_FORMAT_2M16
				|WAVE_FORMAT_2S08|WAVE_FORMAT_2S16))
   ComboBox_AddString(w,"22050");
 if (CommonStandardFormats &	(WAVE_FORMAT_4M08|WAVE_FORMAT_4M16
				|WAVE_FORMAT_4S08|WAVE_FORMAT_4S16))
   ComboBox_AddString(w,"44100");
 if (CommonExtraFormats & 0x000C0C0C)
   ComboBox_AddString(w,"48000");
 if (CommonExtraFormats & 0x00303030)
   ComboBox_AddString(w,"96000");
 if (CommonExtraFormats & 0x00C0C0C0)
   ComboBox_AddString(w,"192000");
 if (!buf[0]) ComboBox_GetLBText(w,ComboBox_GetCount(w)-1,buf);
 SetWindowText(w,buf);

 w=GetDlgItem(Dlg,18);		// "Number of bits per sample"
 GetWindowText(w,buf,elemof(buf));
 ComboBox_ResetContent(w);
 if (CommonStandardFormats &	(WAVE_FORMAT_1M08|WAVE_FORMAT_1S08
				|WAVE_FORMAT_2M08|WAVE_FORMAT_2S08
				|WAVE_FORMAT_4M08|WAVE_FORMAT_4S08))
   ComboBox_AddString(w,"8");
 if (CommonStandardFormats &	(WAVE_FORMAT_1M16|WAVE_FORMAT_1S16
				|WAVE_FORMAT_2M16|WAVE_FORMAT_2S16
				|WAVE_FORMAT_4M16|WAVE_FORMAT_4S16))
   ComboBox_AddString(w,"16");
 if (CommonExtraFormats & 0x00AAAAAA)
   ComboBox_AddString(w,"24");
 if (!buf[0]) ComboBox_GetLBText(w,ComboBox_GetCount(w)-1,buf);
 SetWindowText(w,buf);
}

// Anzahl und Größe der Puffer (Latenzzeit...)
UINT numBuffers, sizBuffers;
PWAVEHDR InHdr, OutHdr;
PBYTE Buffers;
HWAVEIN hwi;
HWAVEOUT hwo;
DWORD balance;	// counts the number of buffers in the wave input device (later: array)
DWORD flags;

void CALLBACK waveInProc(HWAVEIN hwi, UINT Msg, DWORD Inst, DWORD Param1, DWORD Param2) {
 switch (Msg) {
  case WIM_DATA: {
   waveOutWrite(hwo,OutHdr+((LPWAVEHDR)Param1)->dwUser,sizeof(WAVEHDR));
   if (InterlockedDecrement(&balance)==0) flags|=1;	// underflow
  }break;
 }
}

void CALLBACK waveOutProc(HWAVEOUT hwo, UINT Msg, DWORD Inst, DWORD Param1, DWORD Param2) {
 switch (Msg) {
  case WOM_DONE: {
   waveInAddBuffer(hwi,InHdr+((LPWAVEHDR)Param1)->dwUser,sizeof(WAVEHDR));
   if (InterlockedIncrement(&balance)==(int)numBuffers-1) flags|=2;	// overflow
  }break;
 }
}

bool StartCopy(HWND Dlg) {
 DWORD i;
 WAVEFORMATEX wfe;
 if (!InNum) return false;
 if (!OutNum) return false;
 MakeWaveFormat(
   GetDlgItemInt(Dlg,16,NULL,FALSE),
   GetDlgItemInt(Dlg,17,NULL,FALSE),
   GetDlgItemInt(Dlg,18,NULL,FALSE),&wfe);
 if (waveInOpen(&hwi,InList[0],&wfe,(DWORD)waveInProc,0,CALLBACK_FUNCTION)) return false;
 if (waveOutOpen(&hwo,OutList[0],&wfe,(DWORD)waveOutProc,0,CALLBACK_FUNCTION)) return false;
 numBuffers=GetDlgItemInt(Dlg,19,NULL,FALSE);
 sizBuffers=((GetDlgItemInt(Dlg,20,NULL,FALSE)
	*wfe.nAvgBytesPerSec/numBuffers/1000
	+wfe.nBlockAlign-1)/wfe.nBlockAlign)*wfe.nBlockAlign;
 InHdr=LocalAlloc(LPTR,sizeof(WAVEHDR)*numBuffers);
 OutHdr=LocalAlloc(LPTR,sizeof(WAVEHDR)*numBuffers);
 Buffers=LocalAlloc(LPTR,sizBuffers*numBuffers);
// 8 bit data is 80h centered, so fill buffer with silence to prevent "plopp" sound at startup.
// Data for more bits is zero centered.
 if (wfe.wBitsPerSample==8) RtlFillMemory(Buffers,sizBuffers*numBuffers,0x80);
 balance=numBuffers>>1;
 for (i=0; i<numBuffers; i++) {
  InHdr[i].lpData = Buffers+i*sizBuffers;
  InHdr[i].dwBufferLength = sizBuffers;
  InHdr[i].dwUser = i;
  if (waveInPrepareHeader(hwi,InHdr+i,sizeof(WAVEHDR))) return false;
  OutHdr[i].lpData = Buffers+i*sizBuffers;
  OutHdr[i].dwBufferLength = sizBuffers;
  OutHdr[i].dwUser = i;
  if (waveOutPrepareHeader(hwo,OutHdr+i,sizeof(WAVEHDR))) return false;
 }
 waveOutPause(hwo);
 for (i=0; i<balance; i++) if (waveInAddBuffer(hwi,InHdr+i,sizeof(WAVEHDR))) return false;
 for (; i<numBuffers; i++) if (waveOutWrite(hwo,OutHdr+i,sizeof(WAVEHDR))) return false;	// empty buffer for now 
 if (waveInStart(hwi)) return false;	// start streaming same time
 waveOutRestart(hwo);
 return true;
}

bool StopCopy(void) {
 DWORD i;
 bool ret=true;
 waveOutPause(hwo);
 if (hwi && waveInReset(hwi)) ret=false;
 if (hwo && waveOutReset(hwo)) ret=false;
 for (i=0; i<numBuffers; i++) {
  if (hwi && waveInUnprepareHeader(hwi,InHdr+i,sizeof(WAVEHDR))) ret=false;
  if (hwo && waveOutUnprepareHeader(hwo,OutHdr+i,sizeof(WAVEHDR))) ret=false;
 }
 if (hwo && waveOutClose(hwo)) ret=false;	hwo=0;
 if (hwi && waveInClose(hwi)) ret=false;	hwi=0;
 if (Buffers && LocalFree(Buffers)) ret=false;	Buffers=NULL;
 if (OutHdr && LocalFree(OutHdr)) ret=false;	OutHdr=NULL;
 if (InHdr && LocalFree(InHdr)) ret=false;	InHdr=NULL;
 return ret;
}

BOOL CALLBACK MainDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
 switch (Msg) {
  case WM_INITDIALOG: {
   SetDlgItemInt(Wnd,19,8,FALSE);
   SetDlgItemInt(Wnd,20,100,FALSE);
   SendDlgItemMessage(Wnd,14,PBM_SETRANGE32,0,8);
   SendMessage(Wnd,WM_TIMER,WM_DEVICECHANGE,0);
  }return TRUE;

  case WM_DEVICECHANGE: SetTimer(Wnd,Msg,1500,NULL); break;

  case WM_TIMER: switch (wParam) {
   case WM_DEVICECHANGE: {
    KillTimer(Wnd,wParam);
    FillInputDevices(GetDlgItem(Wnd,10));
    FillOutputDevices(GetDlgItem(Wnd,11));
   }break;
   case 101: {	// Aktualisierung Overflow/Underflow-Anzeige
    CheckDlgButton(Wnd,12,flags&1);
    CheckDlgButton(Wnd,13,(flags>>1)&1);
    flags=0;
    SendDlgItemMessage(Wnd,14,PBM_SETPOS,balance,0);
   }break;
  }

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case IDOK: {
    static TCHAR RunButtonText[32];
    if (!hwi) {
     if (StartCopy(Wnd)) {
      TCHAR StopButtonText[32];
      GetWindowText((HWND)lParam,RunButtonText,elemof(RunButtonText));
      LoadString(0,2,StopButtonText,elemof(StopButtonText));
      SetWindowText((HWND)lParam,StopButtonText);
      SetTimer(Wnd,101,200,NULL);
     }else MessageBeep(MB_ICONHAND);
    }else{
     StopCopy();
     SetWindowText((HWND)lParam,RunButtonText);
     KillTimer(Wnd,101);
     SendDlgItemMessage(Wnd,14,PBM_SETPOS,0,0);
    }
   }break;
   case IDCANCEL: EndDialog(Wnd,wParam); break;
   case 10: switch (HIWORD(wParam)) {
    case LBN_SELCHANGE: {
     InNum=ListBox_GetSelItems((HWND)lParam,elemof(InList),InList);
     FillWaveformCharacteristics(Wnd);
     if (!InHdr) EnableWindow(GetDlgItem(Wnd,1),InNum && OutNum);
    }break;
   }break;
   case 11: switch (HIWORD(wParam)) {
    case LBN_SELCHANGE: {
     OutNum=ListBox_GetSelItems((HWND)lParam,elemof(OutList),OutList);
     FillWaveformCharacteristics(Wnd);
     if (!InHdr) EnableWindow(GetDlgItem(Wnd,1),InNum && OutNum);
    }
   }break;
  }
 }
 return FALSE;
}

void CALLBACK WinMainCRTStartup(void) {
 InitCommonControls();
 ExitProcess(DialogBox(0,MAKEINTRESOURCE(100),0,MainDlgProc));
}
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded