258 lines
6.6 KiB
C
258 lines
6.6 KiB
C
//Copyright 2015-2020 <>< Charles Lohr under the ColorChord License, MIT/x11 license or NewBSD Licenses.
|
|
|
|
#include <windows.h>
|
|
#include "CNFA.h"
|
|
#include "os_generic.h"
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <mmsystem.h>
|
|
#include <stdlib.h>
|
|
|
|
//Include -lwinmm, or, C:/windows/system32/winmm.dll
|
|
|
|
#if defined(WINDOWS) || defined(WIN32) || defined(WIN64) \
|
|
|| defined(_WIN32) || defined(_WIN64)
|
|
#ifndef strdup
|
|
#define strdup _strdup
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(WIN32) && !defined( TCC )
|
|
#pragma comment(lib,"winmm.lib")
|
|
#endif
|
|
|
|
#define BUFFS 3
|
|
|
|
struct CNFADriverWin
|
|
{
|
|
//Standard header - must remain.
|
|
void (*CloseFn)( void * object );
|
|
int (*StateFn)( void * object );
|
|
CNFACBType callback;
|
|
short channelsPlay;
|
|
short channelsRec;
|
|
int spsPlay;
|
|
int spsRec;
|
|
void * opaque;
|
|
|
|
char * sInputDev;
|
|
char * sOutputDev;
|
|
|
|
int buffer;
|
|
int isEnding;
|
|
int GOBUFFRec;
|
|
int GOBUFFPlay;
|
|
|
|
int recording;
|
|
int playing;
|
|
|
|
HWAVEIN hMyWaveIn;
|
|
HWAVEOUT hMyWaveOut;
|
|
WAVEHDR WavBuffIn[BUFFS];
|
|
WAVEHDR WavBuffOut[BUFFS];
|
|
};
|
|
|
|
|
|
static struct CNFADriverWin * w;
|
|
|
|
void CloseCNFAWin( void * v )
|
|
{
|
|
struct CNFADriverWin * r = (struct CNFADriverWin *)v;
|
|
int i;
|
|
|
|
if( r )
|
|
{
|
|
if( r->hMyWaveIn )
|
|
{
|
|
waveInStop(r->hMyWaveIn);
|
|
waveInReset(r->hMyWaveIn);
|
|
for ( i=0;i<BUFFS;i++)
|
|
{
|
|
waveInUnprepareHeader(r->hMyWaveIn,&(r->WavBuffIn[i]),sizeof(WAVEHDR));
|
|
free ((r->WavBuffIn[i]).lpData);
|
|
}
|
|
waveInClose(r->hMyWaveIn);
|
|
}
|
|
|
|
if( r->hMyWaveOut )
|
|
{
|
|
waveOutPause(r->hMyWaveOut);
|
|
waveOutReset(r->hMyWaveOut);
|
|
|
|
for ( i=0;i<BUFFS;i++)
|
|
{
|
|
waveInUnprepareHeader(r->hMyWaveIn,&(r->WavBuffOut[i]),sizeof(WAVEHDR));
|
|
free ((r->WavBuffOut[i]).lpData);
|
|
}
|
|
waveInClose(r->hMyWaveIn);
|
|
waveOutClose(r->hMyWaveOut);
|
|
}
|
|
free( r );
|
|
}
|
|
}
|
|
|
|
int CNFAStateWin( void * v )
|
|
{
|
|
struct CNFADriverWin * soundobject = (struct CNFADriverWin *)v;
|
|
|
|
return soundobject->recording | (soundobject->playing?2:0);
|
|
}
|
|
|
|
void CALLBACK HANDLEMIC(HWAVEIN hwi, UINT umsg, DWORD dwi, DWORD hdr, DWORD dwparm)
|
|
{
|
|
int ctr;
|
|
int ob;
|
|
long cValue;
|
|
unsigned int maxWave=0;
|
|
|
|
if (w->isEnding) return;
|
|
|
|
switch (umsg)
|
|
{
|
|
case MM_WIM_OPEN:
|
|
printf( "Mic Open.\n" );
|
|
w->recording = 1;
|
|
break;
|
|
|
|
case MM_WIM_DATA:
|
|
ob = (w->GOBUFFRec+(BUFFS))%BUFFS;
|
|
w->callback( (struct CNFADriver*)w, 0, (short*)(w->WavBuffIn[w->GOBUFFRec]).lpData, 0, w->buffer );
|
|
waveInAddBuffer(w->hMyWaveIn,&(w->WavBuffIn[w->GOBUFFRec]),sizeof(WAVEHDR));
|
|
w->GOBUFFRec = ( w->GOBUFFRec + 1 ) % BUFFS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void CALLBACK HANDLESINK(HWAVEIN hwi, UINT umsg, DWORD dwi, DWORD hdr, DWORD dwparm)
|
|
{
|
|
int ctr;
|
|
long cValue;
|
|
unsigned int maxWave=0;
|
|
|
|
if (w->isEnding) return;
|
|
|
|
switch (umsg)
|
|
{
|
|
case MM_WOM_OPEN:
|
|
printf( "Sink Open.\n" );
|
|
w->playing = 1;
|
|
break;
|
|
|
|
case MM_WOM_DONE:
|
|
w->callback( (struct CNFADriver*)w, (short*)(w->WavBuffOut[w->GOBUFFPlay]).lpData, 0, w->buffer, 0 );
|
|
waveOutWrite( w->hMyWaveOut, &(w->WavBuffOut[w->GOBUFFPlay]),sizeof(WAVEHDR) );
|
|
w->GOBUFFPlay = ( w->GOBUFFPlay + 1 ) % BUFFS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static struct CNFADriverWin * InitWinCNFA( struct CNFADriverWin * r )
|
|
{
|
|
int i;
|
|
WAVEFORMATEX wfmt;
|
|
memset( &wfmt, 0, sizeof(wfmt) );
|
|
printf ("WFMT Size (debugging temp for TCC): %llu\n", sizeof(wfmt) );
|
|
printf( "WFMT: %d %d %d\n", r->channelsRec, r->spsRec, r->spsRec * r->channelsRec );
|
|
w = r;
|
|
|
|
wfmt.wFormatTag = WAVE_FORMAT_PCM;
|
|
wfmt.nChannels = r->channelsRec;
|
|
wfmt.nAvgBytesPerSec = r->spsRec * r->channelsRec;
|
|
wfmt.nBlockAlign = r->channelsRec * 2;
|
|
wfmt.nSamplesPerSec = r->spsRec;
|
|
wfmt.wBitsPerSample = 16;
|
|
wfmt.cbSize = 0;
|
|
|
|
long dwdeviceR, dwdeviceP;
|
|
dwdeviceR = r->sInputDev?atoi(r->sInputDev):WAVE_MAPPER;
|
|
dwdeviceP = r->sOutputDev?atoi(r->sOutputDev):WAVE_MAPPER;
|
|
|
|
if( r->channelsRec )
|
|
{
|
|
printf( "In Wave Devs: %d; WAVE_MAPPER: %d; Selected Input: %ld\n", waveInGetNumDevs(), WAVE_MAPPER, dwdeviceR );
|
|
int p = waveInOpen(&r->hMyWaveIn, dwdeviceR, &wfmt, (intptr_t)(&HANDLEMIC), 0, CALLBACK_FUNCTION);
|
|
if( p )
|
|
{
|
|
fprintf( stderr, "Error performing waveInOpen. Received code: %d\n", p );
|
|
}
|
|
printf( "waveInOpen: %d\n", p );
|
|
for ( i=0;i<BUFFS;i++)
|
|
{
|
|
memset( &(r->WavBuffIn[i]), 0, sizeof(r->WavBuffIn[i]) );
|
|
(r->WavBuffIn[i]).dwBufferLength = r->buffer*2*r->channelsRec;
|
|
(r->WavBuffIn[i]).dwLoops = 1;
|
|
(r->WavBuffIn[i]).lpData=(char*) malloc(r->buffer*r->channelsRec*2);
|
|
printf( "buffer gen size: %d: %p\n", r->buffer*r->channelsRec*2, (r->WavBuffIn[i]).lpData );
|
|
p = waveInPrepareHeader(r->hMyWaveIn,&(r->WavBuffIn[i]),sizeof(WAVEHDR));
|
|
printf( "WIPr: %d\n", p );
|
|
waveInAddBuffer(r->hMyWaveIn,&(r->WavBuffIn[i]),sizeof(WAVEHDR));
|
|
printf( "WIAr: %d\n", p );
|
|
}
|
|
p = waveInStart(r->hMyWaveIn);
|
|
if( p )
|
|
{
|
|
fprintf( stderr, "Error performing waveInStart. Received code %d\n", p );
|
|
}
|
|
}
|
|
|
|
wfmt.nChannels = r->channelsPlay;
|
|
wfmt.nAvgBytesPerSec = r->spsPlay * r->channelsPlay;
|
|
wfmt.nBlockAlign = r->channelsPlay * 2;
|
|
wfmt.nSamplesPerSec = r->spsPlay;
|
|
|
|
if( r->channelsPlay )
|
|
{
|
|
printf( "Out Wave Devs: %d; WAVE_MAPPER: %d; Selected Input: %ld\n", waveOutGetNumDevs(), WAVE_MAPPER, dwdeviceP );
|
|
int p = waveOutOpen( &r->hMyWaveOut, dwdeviceP, &wfmt, (intptr_t)(void*)(&HANDLESINK), (intptr_t)r, CALLBACK_FUNCTION);
|
|
if( p )
|
|
{
|
|
fprintf( stderr, "Error performing waveOutOpen. Received code: %d\n", p );
|
|
}
|
|
printf( "waveOutOpen: %d\n", p );
|
|
for ( i=0;i<BUFFS;i++)
|
|
{
|
|
memset( &(r->WavBuffOut[i]), 0, sizeof(r->WavBuffOut[i]) );
|
|
(r->WavBuffOut[i]).dwBufferLength = r->buffer*2*r->channelsPlay;
|
|
(r->WavBuffOut[i]).dwLoops = 1;
|
|
int size = r->buffer*r->channelsPlay*2;
|
|
char * buf = (r->WavBuffOut[i]).lpData=(char*) malloc(size);
|
|
memset( buf, 0, size );
|
|
p = waveOutPrepareHeader(r->hMyWaveOut,&(r->WavBuffOut[i]),sizeof(WAVEHDR));
|
|
waveOutWrite( r->hMyWaveOut, &(r->WavBuffOut[i]),sizeof(WAVEHDR));
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
void * InitCNFAWin( CNFACBType cb, const char * your_name, int reqSPSPlay, int reqSPSRec, int reqChannelsPlay, int reqChannelsRec, int sugBufferSize, const char * outputSelect, const char * inputSelect, void * opaque )
|
|
{
|
|
struct CNFADriverWin * r = (struct CNFADriverWin *)malloc( sizeof( struct CNFADriverWin ) );
|
|
memset( r, 0, sizeof(*r) );
|
|
r->CloseFn = CloseCNFAWin;
|
|
r->StateFn = CNFAStateWin;
|
|
r->callback = cb;
|
|
r->opaque = opaque;
|
|
r->spsPlay = reqSPSPlay;
|
|
r->spsRec = reqSPSRec;
|
|
r->channelsPlay = reqChannelsPlay;
|
|
r->channelsRec = reqChannelsRec;
|
|
r->buffer = sugBufferSize;
|
|
r->sInputDev = inputSelect?strdup(inputSelect):0;
|
|
r->sOutputDev = outputSelect?strdup(outputSelect):0;
|
|
|
|
r->recording = 0;
|
|
r->playing = 0;
|
|
r->isEnding = 0;
|
|
r->GOBUFFPlay = 0;
|
|
r->GOBUFFRec = 0;
|
|
|
|
return InitWinCNFA(r);
|
|
}
|
|
|
|
REGISTER_CNFA( WinCNFA, 10, "WIN", InitCNFAWin );
|
|
|