Sign in to follow this  
FreeTutorialNewbie

waveInOpen=confusionMaxOpen

Recommended Posts

i checked out msdn but all they do is declare stuff they leave no examples or indicate the correct manner at wich you go about recording audio using the wave api in windows (mmsystem.h) here is what i got, its basically a toggled thread that toggles playback and recording..the mode var is set in the window message loop when dialog buttons are pressed 0=playback 1=record DoRun is1 for continue program exec, 0 for quit program, it the means of quiting the entire program set to 0 when the message loop picks up the WM_QUIT message if its not set here its probably global somewhere this function is called as a thread by beginthread(WavePlayBack,2000,&MainData); void WavePlayBack(void){ int PlayTimer=0; char *c="papapapapapapapapapapapapap"; char d[4]; HWAVEOUT outHandle; HWAVEIN inHandle; WAVEFORMATEX waveFormat; waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nChannels = 1; waveFormat.nSamplesPerSec = 8000; waveFormat.wBitsPerSample = 8; waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample/8); waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; waveFormat.cbSize = 0; WAVEHDR waveouthdr, waveinhdr; while(MainData.DoRun){ Sleep(100); if(!MainData.Mode){ if(!waveOutOpen(&outHandle,WAVE_MAPPER,&waveFormat,0,0,CALLBACK_NULL)){ memset(&waveouthdr,0,sizeof(waveouthdr)); waveouthdr.lpData = c; waveouthdr.dwBufferLength = 4; waveouthdr.dwBytesRecorded = 1; waveouthdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; waveouthdr.dwLoops = 1; waveOutPrepareHeader(outHandle,&waveouthdr,sizeof(waveouthdr)); waveOutWrite(outHandle,&waveouthdr,sizeof(waveouthdr)); PlayTimer=0; while(!MainData.Mode){ Sleep(1); PlayTimer++; if((waveouthdr.dwFlags & WHDR_DONE)==WHDR_DONE){ waveouthdr.dwFlags &= ~WHDR_DONE; PlayTimer--; waveOutWrite(outHandle,&waveouthdr,sizeof(waveouthdr)); Sleep(PlayTimer);}} waveOutReset(outHandle); waveOutClose(outHandle);} }else{ if(!waveInOpen(&inHandle,WAVE_MAPPER,&waveFormat,0,0,CALLBACK_NULL)){ memset(&waveinhdr,0,sizeof(waveinhdr)); waveinhdr.lpData = d; waveinhdr.dwBufferLength = 4; waveinhdr.dwBytesRecorded = 1; waveinhdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; waveinhdr.dwLoops = 1; waveInPrepareHeader(inHandle,&waveinhdr,sizeof(waveinhdr)); waveInAddBuffer(inHandle,&waveinhdr,sizeof(waveinhdr)); waveInStart(inHandle); PlayTimer=0; while(MainData.Mode){ Sleep(1); PlayTimer++; if((waveinhdr.dwFlags & WHDR_DONE)==WHDR_DONE){ waveinhdr.dwFlags &= ~WHDR_DONE; PlayTimer--; //see what we have recorded TextOutA(GetDC(MainData.Hwnd),0,0,d,4); waveInReset(inHandle); waveInAddBuffer(inHandle,&waveinhdr,sizeof(waveinhdr)); waveInStart(inHandle); if(PlayTimer>30){ PlayTimer=1;} Sleep(PlayTimer);}} waveInStop(inHandle); waveInReset(inHandle); waveInClose(inHandle); }}}} the playback works its the recording that is messed up i basically gt this far by simply guessing any help would greatly be appreciated

Share this post


Link to post
Share on other sites
Well, let's see.


  1. You're actually displaying the output as text, which seems a bit weird. Better write it to a file so you can actually play it back later and hear what is being recorded.

  2. Recording just 4 bytes at a time? At 8000Hz, mono, 8bit, that's exactly 0.0005 seconds. How can you tell anything from that? Make your buffer something like 128KB to get some meaningful data.

  3. waveinhdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
    waveinhdr.dwLoops = 1;
    .
    The LOOP flags are ignored when recording, so just leave them at 0.

  4. Get rid of the waveInReset call and the waveInStart call immediately following it.

Share this post


Link to post
Share on other sites
thank you for the help,

this is going to be a "team speak wanna bee" and that thread will be responsible for handling the audio playback recording, and it it toggled to support legacy audio drivers

believe it or not i figured out winsock (multithreaded server even) way before any of this wave api stuff clicked in my head

so when you consider that the playback/recording waits for network data to be sent or received, does it begin to make sence? (after the recommended changes ofcourse)

and it will play and record more than4 bytes, its just popping text representation so i can see the actual values change with the recorded sounds, as of now it remains {0,0,0,0} wich looks like 4 filled boxes in ascii

thats also the reason for the crappy audio resolution, trying to work it accross the internet and trying to consider the load on the server,
what audio format to you recommend and how long of a recording in bytes?
(think dialup compatibility please)

for those of you who havent seen or used team speak its a voice communication app used by gamers to keep in touch with freinds while playing games over the internet
the game being played will consume most of the available network bandwidth, so i will have to keep throughput to a minimum

Share this post


Link to post
Share on other sites
after removing what i was told to remove, the text output clearly displays a changing recording buffer.
Thanks alot.

here is the code so far...

i indent my code but all indents are removed here..so it does look messy
i should also comment more often

do you think i should use a pointer to the maindata structure to speed up execution?, or in this case would it matter?

notice the sleep method to keep this thread from useing up the cpu and freezing the computer, also a variable sleep time will be needed since it will run at the same time as some memory and cpu hungry massive 3d accelerated game, meaning if i used a constant sleep time it may be too slow


#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <string.h>
#include <mmsystem.h>
#include <winsock2.h>
#include <stdio.h>
#include <process.h>

#include "elitespeakres.h"

typedef struct{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];} sockaddr_in;

typedef struct{
int Status;
char NetID;
SOCKET Socket;
sockaddr_in SockAddr;
char *UserName;
char *Password;} NETWORK;

typedef struct{
HWND Hwnd;
HINSTANCE Hinst;
int DoRun;
int Mode;
int Status;
MSG Msg;


} MAINDATA;

MAINDATA MainData;

static BOOL CALLBACK DialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
MainData.Mode=1;
return 1;
case IDCANCEL:
MainData.Mode=0;
return 1;}
break;
case WM_CLOSE:
PostQuitMessage(0);
return 1;}
return 0;}


void WavePlayBack(void){
int PlayTimer=0;
char *c="papapapapapapapapapapapapap";
char d[4];
HWAVEOUT outHandle;
HWAVEIN inHandle;
WAVEFORMATEX waveFormat;

waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = 1;
waveFormat.nSamplesPerSec = 8000;
waveFormat.wBitsPerSample = 8;
waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample/8);
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0;

WAVEHDR waveouthdr, waveinhdr;

while(MainData.DoRun){
Sleep(100);
if(!MainData.Mode){
if(!waveOutOpen(&outHandle,WAVE_MAPPER,&waveFormat,0,0,CALLBACK_NULL)){
memset(&waveouthdr,0,sizeof(waveouthdr));
waveouthdr.lpData = c;
waveouthdr.dwBufferLength = 4;
waveouthdr.dwBytesRecorded = 1;
waveouthdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
waveouthdr.dwLoops = 1;
waveOutPrepareHeader(outHandle,&waveouthdr,sizeof(waveouthdr));
waveOutWrite(outHandle,&waveouthdr,sizeof(waveouthdr));
PlayTimer=0;
while(!MainData.Mode){
Sleep(1);
PlayTimer++;
if((waveouthdr.dwFlags & WHDR_DONE)==WHDR_DONE){
waveouthdr.dwFlags &= ~WHDR_DONE;
PlayTimer--;
waveOutWrite(outHandle,&waveouthdr,sizeof(waveouthdr));
Sleep(PlayTimer);}}
waveOutReset(outHandle);
waveOutClose(outHandle);}
}else{
if(!waveInOpen(&inHandle,WAVE_MAPPER,&waveFormat,0,0,CALLBACK_NULL)){
memset(&waveinhdr,0,sizeof(waveinhdr));
waveinhdr.lpData = d;
waveinhdr.dwBufferLength = 4;
waveinhdr.dwBytesRecorded = 1;
waveinhdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
waveinhdr.dwLoops = 1;
waveInPrepareHeader(inHandle,&waveinhdr,sizeof(waveinhdr));
waveInAddBuffer(inHandle,&waveinhdr,sizeof(waveinhdr));
waveInStart(inHandle);
PlayTimer=0;
while(MainData.Mode){
Sleep(1);
PlayTimer++;
if((waveinhdr.dwFlags & WHDR_DONE)==WHDR_DONE){
waveinhdr.dwFlags &= ~WHDR_DONE;
PlayTimer--;
//see what we have recorded
TextOutA(GetDC(MainData.Hwnd),0,0,d,4);
waveInAddBuffer(inHandle,&waveinhdr,sizeof(waveinhdr));
if(PlayTimer>30){
PlayTimer=1;}
Sleep(PlayTimer);}}
waveInStop(inHandle);
waveInReset(inHandle);
waveInClose(inHandle);
}}}}

int APIENTRY WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow){
WNDCLASS wc;
INITCOMMONCONTROLSEX cc;
WSADATA wsadata;
int ret=0;

if(WSAStartup(MAKEWORD(2,1),&wsadata)!=0){
MessageBox(NULL,"This program has encountered an error while attempting \n to initiate windows sockets version 2.1 or higher.", "Critical Error",MB_OK|MB_ICONERROR);
}else{
memset(&MainData,0,sizeof(MAINDATA));
MainData.DoRun=1;
beginthread(WavePlayBack,20000,&MainData);
memset(&wc,0,sizeof(wc));
wc.lpfnWndProc = DefDlgProc;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hinst;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "EliteSpeak";
if(RegisterClass(&wc)){
memset(&cc,0,sizeof(cc));
cc.dwSize = sizeof(cc);
cc.dwICC = 0xffffffff;
InitCommonControlsEx(&cc);
MainData.Hinst=hinst;
if((MainData.Hwnd=CreateDialog(MainData.Hinst,MAKEINTRESOURCE(IDD_MAINDIALOG),NULL,(DLGPROC)DialogFunc))!=NULL){
MainData.DoRun=1;
while(MainData.DoRun){
if(PeekMessage(&MainData.Msg,MainData.Hwnd,0,0,PM_REMOVE)){
if(MainData.Msg.message==WM_QUIT){
MainData.DoRun=0;
}else{
TranslateMessage(&MainData.Msg);
DispatchMessage(&MainData.Msg);}
}else{
Sleep(50);

}}
DestroyWindow(MainData.Hwnd);
}else{
MessageBox(NULL,"This program has encountered an error while \n attempting to create the main window.", "Critical Error",MB_OK|MB_ICONERROR);}
UnregisterClass("EliteSpeak",MainData.Hinst);
}else{
MessageBox(NULL,"This program has encountered an error while \n attempting to register a window class.", "Critical Error",MB_OK|MB_ICONERROR);}
WSACleanup();}
return MainData.Msg.wParam;}

any help would be appreciated, btw this is my first day using gamedev, and its way better than other forums mainly because of its members

Share this post


Link to post
Share on other sites
Quote:
Original post by FreeTutorialNewbie
here is the code so far...
<snip>
i indent my code but all indents are removed here..so it does look messy
i should also comment more often

You should use the [source] and [/source] tags to paste code. That way, indentation is preserved and it is syntax highlighted.

Quote:

do you think i should use a pointer to the maindata structure to speed up execution?, or in this case would it matter?

If maindata is currently a global, then using a pointer will actually slow it down (but we're talking nanoseconds here, so it's not noticeable).

Quote:

notice the sleep method to keep this thread from useing up the cpu and freezing the computer, also a variable sleep time will be needed since it will run at the same time as some memory and cpu hungry massive 3d accelerated game, meaning if i used a constant sleep time it may be too slow

The best way to handle this would be not to poll everything in a thread, but to use a callback. There's a sample on recording audio this way here.

Quote:

any help would be appreciated, btw this is my first day using gamedev, and its way better than other forums mainly because of its members

I've noticed you've been posting a lot already. You should be a little more careful in what you post. It is better to keep silent than to give incorrect advice. The latter tends to make other members rate you down, which decreases your credibility and can even hide your posts from other users, which makes you less likely to get the help you need. Just some friendly advice.

Anyway, welcome to GD!

[Edited by - Kippesoep on August 31, 2005 11:06:37 AM]

Share this post


Link to post
Share on other sites
yea...but for the most part the replies are about simple stuff like running a program that doesnt open a window and painting a bitmap to a windows background

would i have to make the waveheader and buffers global to be able to reach them in the callback or is the callback considered within this thread's scope?

Share this post


Link to post
Share on other sites
Quote:
Original post by FreeTutorialNewbie
would i have to make the waveheader and buffers global to be able to reach them in the callback or is the callback considered within this thread's scope?

Just the waveheader should be sufficient. Normal C++ scoping rules apply. When you use a callback, you eliminate the need for a separate recording thread and seriously reduce the CPU usage.

Share this post


Link to post
Share on other sites
would useing the same callback as my mainwindow work fine, instead of having to make a separate callback function?

would having the callback operation inside the window callback cause periods of nonresponsivenes?

Share this post


Link to post
Share on other sites
Quote:
Original post by FreeTutorialNewbie
would useing the same callback as my mainwindow work fine, instead of having to make a separate callback function?

That should work just the same. Personally, I prefer splitting it up, since I think the window and the sound recording are conceptionally separate, especially if there is no UI change in response to the sound.

Quote:
would having the callback operation inside the window callback cause periods of nonresponsivenes?

It shouldn't.

Share this post


Link to post
Share on other sites
well..at least is my means of opening and using the argument pointer correct?

I couldn't really find tutorials for multithreading..so i kinda poked around in the dark

the reason i proposed handling the wave messages in the winproc
is because according to msdn docs using almost any function inside of waveinproc causes it to hang.
i wouldnt be able to send on the network from within the waveinproc
thats also the reason for making a separate thread, wouldnt calling the send function everytime you get a done buffer kinda slow down the winproc?

basically what the original plan was to handle the entire recording and sending, recieving and playback, and maintaining the socket connection in 1 independant thread

all this while winmain handles fancy smancy window drawing stuff i havent began to put in yet, such as an admin control panel and a settings dialog box, etc.

the plan for the server was to have a thread dedicated to accepting connections, that spun off threads to recv and send until connection is closed
there will be 1 structure given to all threads so when a thread recv's data, it sends it to all connected clients by cycling through each socket in the shared data struct

i actually made 2 separate projects with working winsock code so it should be a matter of copy and paste (i hope..lol)

thank you all who read this and put up with us newbs

ps: if i post code here i allow anybody to use it









Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this