Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Recording and Playing audio.

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
Deltron Z
Expert Cheater
Reputation: 1

Joined: 14 Jun 2009
Posts: 164

PostPosted: Mon Oct 11, 2010 11:07 pm    Post subject: Recording and Playing audio. Reply with quote

I've been looking around for quite a lot now... usually I use MSDN or other sources, but in this case there's not really any good documented sources.
I understand using mciSendString and mciSendCommand can help me record and play sounds easily, but I couldn't get the sound buffer data, and besides, these were slow for me. I've found a source code that is recording, playing and saving the audio to a file, it took a few seconds just to initialize each operation, but I need to work faster because I am trying to create a simple Skype-like software, for now, just a console that records a few seconds and sends the information through the internet.
So far I've managed to understand (poorly) the wave* APIs and successfuly retrived the buffer's content.

Here's what I've done so far:
Code:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <mmsystem.h>
#include <stdio.h>

#pragma comment(lib, "winmm.lib")

#define BUFFER_SIZE        4096 * 2

void Error(LPCSTR Description, DWORD Error)
{
    printf("%s (%u)\n", Error);
}

DWORD Record(/*DWORD dwMilliSeconds*/)
{
    DWORD bytesWritten;
    DWORD dwReturn;
    HANDLE hFile;
    HWAVEIN hWaveIn;
    WAVEHDR waveHeader;
    WAVEFORMATEX waveFormat = {
        WAVE_FORMAT_PCM, //wFormatTag;
        1, //nChannels;
        11025, //nSamplesPerSec;
        11025, //nAvgBytesPerSec;
        1, //nBlockAlign;
        8, //wBitsPerSample,
        0 };

    dwReturn = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, NULL, NULL, CALLBACK_NULL);
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveInOpen", dwReturn);
        return dwReturn;
    }

    waveHeader.dwFlags = 0;
    waveHeader.dwBufferLength = BUFFER_SIZE;
    waveHeader.lpData = new char[waveHeader.dwBufferLength];

    dwReturn = waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(waveHeader));
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveInPrepareHeader", dwReturn);
        return dwReturn;
    }

    dwReturn = waveInAddBuffer(hWaveIn, &waveHeader, sizeof(waveHeader));
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveInAddBuffer", dwReturn);
        return dwReturn;
    }

    dwReturn = waveInStart(hWaveIn);

    for (int i = 0; i < 100; i++)
    {
        Sleep(100);
        if ((waveHeader.dwFlags & WHDR_DONE) == WHDR_DONE)
            break;
    }
    printf("%u\n", waveHeader.dwBytesRecorded);

    hFile = CreateFile(TEXT("recording.wav"), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    //Format taken from:
    //https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
    WriteFile(hFile, "RIFF", 4, &bytesWritten, NULL);
    dwReturn = 36 + waveHeader.dwBytesRecorded * waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
    WriteFile(hFile, &dwReturn, 4, &bytesWritten, NULL);
    WriteFile(hFile, "WAVE", 4, &bytesWritten, NULL);

    WriteFile(hFile, "fmt ", 4, &bytesWritten, NULL);
    dwReturn = 16;
    WriteFile(hFile, &dwReturn, 4, &bytesWritten, NULL);
    WriteFile(hFile, &waveFormat.wFormatTag, 2, &bytesWritten, NULL);
    WriteFile(hFile, &waveFormat.nChannels, 2, &bytesWritten, NULL);
    WriteFile(hFile, &waveFormat.nSamplesPerSec, 4, &bytesWritten, NULL);
    dwReturn = waveFormat.nSamplesPerSec * waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
    WriteFile(hFile, &dwReturn, 4, &bytesWritten, NULL);
    dwReturn = waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
    WriteFile(hFile, &dwReturn, 2, &bytesWritten, NULL);
    WriteFile(hFile, &waveFormat.wBitsPerSample, 2, &bytesWritten, NULL);

    WriteFile(hFile, "data", 4, &bytesWritten, NULL);
    //dwReturn = waveHeader.dwBytesRecorded * waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
    WriteFile(hFile, &waveHeader.dwBytesRecorded, 4, &bytesWritten, NULL);
    WriteFile(hFile, waveHeader.lpData, waveHeader.dwBytesRecorded, &bytesWritten, NULL);
    CloseHandle(hFile);

    waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(waveHeader));
    delete[] waveHeader.lpData;

    waveInClose(hWaveIn);

    return ERROR_SUCCESS;
}

BOOL Play()
{
    DWORD dwReturn;
    HWAVEOUT hWaveOut;
    WAVEHDR waveHeader;
    WAVEFORMATEX waveFormat = {
        WAVE_FORMAT_PCM, //wFormatTag;
        1, //nChannels;
        11025, //nSamplesPerSec;
        11025, //nAvgBytesPerSec;
        1, //nBlockAlign;
        8, //wBitsPerSample,
        0 };

    HANDLE hFile = CreateFile(TEXT("recording.wav"), GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return FALSE;

    dwReturn = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, NULL, NULL, CALLBACK_NULL);
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveOutOpen", dwReturn);
        return dwReturn;
    }

    waveOutSetVolume(hWaveOut, 0xFFFF);

    waveHeader.dwFlags = 0;
    waveHeader.dwBufferLength = BUFFER_SIZE;
    waveHeader.lpData = new char[waveHeader.dwBufferLength];

    SetFilePointer(hFile, 44, 0, SEEK_SET); //data
    ReadFile(hFile, waveHeader.lpData, waveHeader.dwBufferLength, &dwReturn, NULL);
    CloseHandle(hFile);

    dwReturn = waveOutPrepareHeader(hWaveOut, &waveHeader, sizeof(waveHeader));
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveOutPrepareHeader", dwReturn);
        return dwReturn;
    }

    dwReturn = waveOutWrite(hWaveOut, &waveHeader, sizeof(waveHeader));
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveOutWrite", dwReturn);
        return dwReturn;
    }

    waveOutUnprepareHeader(hWaveOut, &waveHeader, sizeof(waveHeader));
    delete[] waveHeader.lpData;

    while ((waveHeader.dwFlags & WHDR_DONE) != WHDR_DONE);

    waveOutClose(hWaveOut);

    return ERROR_SUCCESS;
}

int main()
{
    Record(/*15000*/);
    //Play();
    printf("Done!\n");

    return 0;
}

Needs a little cleaning and improvment, but after I'll get it working.

The Record function works fine. it's the Play function that's giving me a hard time. I just have no idea what is it that I do wrong?
I thought maybe the input wasn't good or in the correct format, so I've created a WAV file by adding a few lines of code quickly but it seems to work when I play it using a media player.
I also tried adjusting the volume with code, double checked for errors, nothing.


Last edited by Deltron Z on Tue Oct 12, 2010 10:35 am; edited 2 times in total
Back to top
View user's profile Send private message
HomerSexual
Grandmaster Cheater Supreme
Reputation: 5

Joined: 03 Feb 2007
Posts: 1657

PostPosted: Mon Oct 11, 2010 11:13 pm    Post subject: Reply with quote

if this were in java i'd help you since i just wrote a program to do that! I don't know how in C++ Razz

in java it's basically
1. get handle to mic mixer from system
2. define targetdataline and crap like that
3. record until line is empty (which it will never be so you have a stop/start button)
4. write all that to a buffer which can be used for playback, writing audio file, etc

_________________
Back to top
View user's profile Send private message
Deltron Z
Expert Cheater
Reputation: 1

Joined: 14 Jun 2009
Posts: 164

PostPosted: Tue Oct 12, 2010 10:29 am    Post subject: Reply with quote

Thanks for trying to help, but it sounds very different from the APIs I have.
I don't really write in Java, I guess I wouldn't have any problems writing in it, but I just want to learn about these APIs before using a higher level language such as Java or C# which probably contains a set of classes ready for use.
I just wonder why recording works perfectly fine but playing it doesn't work. the only thing I can think of is that I passed wrong parameters or needed a call to some other API first, because the documentation isn't very helpful.


Edit:
Oh man... I wrote better things drunk... this is the last time I'm writing stuff at 5:00 AM!
I deleted the buffer and used Unprepare Header BEFORE I let the buffer play... I just moved the loop before that.

Who am I kidding, you always write the best codes at night! Razz Razz

Now it's like this:
Code:
DWORD Play()
{
    DWORD dwReturn;
    HWAVEOUT hWaveOut;
    WAVEHDR waveHeader;
    WAVEFORMATEX waveFormat = {
        WAVE_FORMAT_PCM, //wFormatTag;
        1, //nChannels;
        11025, //nSamplesPerSec;
        11025, //nAvgBytesPerSec;
        1, //nBlockAlign;
        8, //wBitsPerSample,
        0 };

    HANDLE hFile = CreateFile(TEXT("C:\\recording.wav"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return (DWORD)INVALID_HANDLE_VALUE;

    dwReturn = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, NULL, NULL, CALLBACK_NULL);
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveOutOpen", dwReturn);
        return dwReturn;
    }

    //waveOutSetVolume(hWaveOut, 0xFFFF);

    waveHeader.dwFlags = 0;
    waveHeader.dwBufferLength = BUFFER_SIZE;
    waveHeader.lpData = new char[waveHeader.dwBufferLength];

    SetFilePointer(hFile, 44, 0, SEEK_SET); //data
    ReadFile(hFile, waveHeader.lpData, waveHeader.dwBufferLength, &dwReturn, NULL);
    CloseHandle(hFile);

    dwReturn = waveOutPrepareHeader(hWaveOut, &waveHeader, sizeof(waveHeader));
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveOutPrepareHeader", dwReturn);
        return dwReturn;
    }

    dwReturn = waveOutWrite(hWaveOut, &waveHeader, sizeof(waveHeader));
    if (dwReturn != ERROR_SUCCESS)
    {
        Error("waveOutWrite", dwReturn);
        return dwReturn;
    }

    do
        Sleep(100);
    while ((waveHeader.dwFlags & WHDR_DONE) != WHDR_DONE);

    waveOutUnprepareHeader(hWaveOut, &waveHeader, sizeof(waveHeader));
    delete[] waveHeader.lpData;

    waveOutClose(hWaveOut);

    return ERROR_SUCCESS;
}


Notice I've changed the return value, because it used to return BOOL but I returned ERROR_SUCCESS which is 0 which is FALSE.
Now I'm returning (DWORD)-1 when hFile == INVALID_HANDLE_VALUE and the last error when another error has occurred.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites