0
0

I’d like to construct a simple app that shows a spectrum analyzer and a few pieces of data (VU levels, etc.) on INCOMING audio (that is, data from my microphone).

Searching the FAQs here, it looks like others have had similar questions and been led to review the ‘record’ example – which has the ability to play while recording.

OK – fair enough. Poking around a bit in the record example’s main.cpp I see the ID_RECORD case (launching the recording) and decide to try to mod it a bit…

It’s been awhile (more than a year) since I’ve played with FMOD so… be gentle please :)

To setup the simultaneous record/play, I do two things:
1) set the looping param to TRUE
2) Add the PlaySound in the Record button section

[code:1327p4ml]
case ID_RECORD :
FSOUND_Record_StartSample(samp, TRUE);
channel = FSOUND_PlaySound(FSOUND_FREE, samp);
FSOUND_SetVolume(channel, 0); // don’t want to hear it
break;
[/code:1327p4ml]

Now I need to sync the two (input and output). To do this, I’m trying:
FSOUND_SetCurrentPosition(channel, FSOUND_Record_GetPosition());

Finally, to test this mess, I try grabbing the VU levels of the audio as it comes in – all within the WM_PAINT (I know – a thousand lashes with a wet noodle – very ugly):

[code:1327p4ml]
case WM_PAINT :
{
RECT rt;
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rt);
float vuval, lVU, rVU = 0.0f;

        Common_SetTextY(text_y);

        FSOUND_SetCurrentPosition(channel, FSOUND_Record_GetPosition());

        Common_Printf(hdc, &rt, "Record   Position %7d / %7d    ", FSOUND_Record_GetPosition(), FSOUND_Sample_GetLength(samp));
        Common_Printf(hdc, &rt, "Playback Position %7d / %7d    ", FSOUND_GetCurrentPosition(channel), FSOUND_Sample_GetLength(samp));

         FSOUND_GetCurrentLevels(channel, &lVU, &rVU);
        vuval = (lVU+rVU) * 0.5f;
        vuval *= 18.0f;         
        Common_Printf(hdc, &rt, "lVU  %f", (int) (lVU));          
        Common_Printf(hdc, &rt, "VU   %f", vuval);    


        EndPaint(hWnd, &ps);
        break;
    }

[/code:1327p4ml]

Problems with where I am in this project:
1) Starting the app and hitting the record button… I see the record counter and play counter both running, but eventually the play counter stops at 0. Do I need to tell it to loop? How?

2) The VU “levels” do not do anything until I hit the play button.

Any help is appreciated!

  • You must to post comments
0
0

Thanks for the reply Brett…

OK – got rid of the FSOUND_SetCurrentPosition and FSOUND_SetVolume 0. I guess I was trying to get rid of the playback/echo effect of running both record/play at the same time. (the setcurrentposition was a lame attempt to keep them in-sync, knowing that I’d move it out of PAINT sometime).

How can I eliminate this persistent echo?

  • You must to post comments
0
0

I now see where I went astray…

1) I (incorrectly) assumed that the WinCE record example was the same as the Win32 record example. They are vastly different beasts. The WinCE record does not include code to sync the record/playback, for example. 😳

2) The nasty echo I was hearing was due to the speaker output being picked up by the built-in mic (again, sorry for not mentioning that this was a PDA – I didn’t think that it mattered in the case when I first asked). If I mute the PDA (system volume control), or use headphones – the problem goes away. Again, I want to analyze the incoming audio… so perhaps I’ll just have to plug in headphones when I use this unless I can find a way to mute it programatically.

3) Now that I know to look at the Win32 example, I’ve taken that and munged it into the WinCE version. My current attempt is below. Note that the setfrequency code is in the update_positions section – but commented out as it was generating an odd response (speeding up and slowing down). So, I’d like to fix that.

4) Finally, spectrum analysis of the playback loop. Perhaps I should look next at wedging PlotEqualizer() from the 3d2 example into this and I’d be close. Thoughts?

[code:3stfluoz]
/*===============================================================================================
RECORD.EXE
Copyright (c), Firelight Technologies Pty, Ltd 1999-2003.

This example demonstrates some fundamental FMOD usage, loading and playing samples and a
music file, and calling some runtime manipulation and information functions.
===============================================================================================*/

include <windows.h>

include <commctrl.h>

include "resource.h"

include "../common/common.h"

include "../../api/inc/fmod.h"

include "../../api/inc/fmod_errors.h"

define ID_RECORD 0x8801

define ID_PLAY 0x8802

define RECORDRATE 22050

define RECORDLEN (RECORDRATE * 1) /* 1 second at RECORDRATE khz */

TCHAR szAppName[] = L"RECORD";
TCHAR szAppTitle[] = L"FMOD – record";

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

FSOUND_SAMPLE *samp = NULL;
int channel = -1;

int originalfreq;
float vuval, lVU, rVU = 1.0f;

define RECORD_DELAY_MS 25

define RECORD_DELAY_SAMPLES (RECORDRATE * RECORD_DELAY_MS / 1000)

void update_positions ();

/*
[
[DESCRIPTION]

[PARAMETERS]

[RETURN_VALUE]

[REMARKS]

[SEE_ALSO]

]
*/
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{

MSG msg;

hInst = hInstance;

if (!Common_InitInstance(nCmdShow))
{
    return FALSE;
}

while (GetMessage(&amp;msg, NULL, 0, 0)) 
{
    TranslateMessage(&amp;msg);
    DispatchMessage(&amp;msg);
    update_positions ();
}

return msg.wParam;

}

/*
[
[DESCRIPTION]

[PARAMETERS]

[RETURN_VALUE]

[REMARKS]

[SEE_ALSO]

]
*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
static int text_y = 0;
int retrycount = 0;

switch (message) 
{
    case WM_CREATE :
    {
        Common_WM_CREATE(hWnd);

        while (!FSOUND_Init(32000, 32, FSOUND_INIT_ACCURATEVULEVELS) &amp;&amp; retrycount &lt; 10)
        {
            Sleep(100);
            retrycount++;
        }

        if (retrycount == 10)
        {
            Common_DisplayError();
        }
        else
        {
            samp = FSOUND_Sample_Alloc(FSOUND_UNMANAGED, RECORDLEN, FSOUND_STEREO | FSOUND_16BITS , RECORDRATE, 255, 128, 255);
            if (!samp)
            {
                Common_DisplayError();
                SendMessage(hWnd, WM_CLOSE, 0, 0);
                return 0;
            }
        }

        int y = 1;
        int bh = Common_GetButtonHeight(hWnd) + 1;
        Common_CreateButton(hWnd, L&quot;Record&quot;, 0, y, -1, -1, ID_RECORD);
        Common_CreateButton(hWnd, L&quot;Play&quot;, 0, y += bh, -1, -1, ID_PLAY);
        text_y = y + (bh * 2);

        break;
    }

    case WM_COMMAND :
    {
        wmId    = LOWORD(wParam); 
        wmEvent = HIWORD(wParam); 

        switch (wmId)
        {
            case IDM_HELP_ABOUT :
                Common_About(hWnd);
                break;
            case ID_RECORD :
                FSOUND_Sample_SetMode(samp, FSOUND_LOOP_NORMAL); 
                FSOUND_Record_StartSample(samp, TRUE);
                channel = FSOUND_PlaySound(FSOUND_FREE, samp);
                break;
            case ID_PLAY :
                FSOUND_Record_Stop();                   
                channel = FSOUND_PlaySound(FSOUND_FREE, samp);
                break;

            case IDM_FILE_EXIT :
                DestroyWindow(hWnd);
                break;

            default:
               return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    }

    case WM_TIMER :
        Common_WM_TIMER(hWnd);
        break;

    case WM_PAINT :
    {
        RECT rt;
        HDC hdc;
        PAINTSTRUCT ps;


        hdc = BeginPaint(hWnd, &amp;ps);
        GetClientRect(hWnd, &amp;rt);
        Common_SetTextY(text_y);
        Common_Printf(hdc, &amp;rt, &quot;Record   Position %7d / %7d    &quot;, FSOUND_Record_GetPosition(), FSOUND_Sample_GetLength(samp));
        Common_Printf(hdc, &amp;rt, &quot;Playback Position %7d / %7d    &quot;, FSOUND_GetCurrentPosition(channel), FSOUND_Sample_GetLength(samp));
        Common_Printf(hdc, &amp;rt, &quot;lVU  %f&quot;, lVU);
        Common_Printf(hdc, &amp;rt, &quot;rVU  %f&quot;, rVU);
        Common_Printf(hdc, &amp;rt, &quot;VU   %f&quot;, vuval);    
        EndPaint(hWnd, &amp;ps);
        break;
    }

    case WM_CLOSE:
    case WM_DESTROY:
    {
        FSOUND_Sample_Free(samp);
        FSOUND_Close();

        Common_WM_CLOSE(hWnd);
        break;
    }
    default:
    {
        return DefWindowProc(hWnd, message, wParam, lParam);
    }

}
return 0;
}

void update_positions ()
{

// update the cursors
int playpos, recordpos, diff;
static int oldrecordpos = 0, oldplaypos = 0;
originalfreq = FSOUND_GetFrequency(channel);

playpos = FSOUND_GetCurrentPosition(channel);
recordpos = FSOUND_Record_GetPosition();

/* 
    NOTE : As the recording and playback frequencies arent guarranteed to be exactly in 
    sync, we have to adjust the playback frequency to keep the 2 cursors just enough 
    apart not to overlap. (and sound corrupted)
    This code tries to keep it inside a reasonable size window just behind the record
    cursor. ie [........|play window|&lt;-delay-&gt;|&lt;-Record cursor.............] 
*/

/*
    Dont do this code if either of the cursors just wrapped
*/

/*  
if (playpos &gt; oldplaypos &amp;&amp; recordpos &gt; oldrecordpos) 
{
    diff = playpos - recordpos;

    if (diff &gt; -RECORD_DELAY_SAMPLES)
    {
        FSOUND_SetFrequency(channel, originalfreq - 1000);  // slow it down 
    }
    else if (diff &lt; -(RECORD_DELAY_SAMPLES * 2))
    {
        FSOUND_SetFrequency(channel, originalfreq + 1000);  // speed it up
    }
    else
    {
        FSOUND_SetFrequency(channel, originalfreq); 
    }
}

oldplaypos = playpos;
oldrecordpos = recordpos;


*/


// Update the VU Levels based on what's playing now
FSOUND_GetCurrentLevels(channel, &amp;lVU, &amp;rVU);
vuval = (lVU+rVU) * 0.5f;
vuval *= 18.0f;         

}

[/code:3stfluoz]

Thanks again!

  • You must to post comments
0
0

Now I see:
[url:2olnwz4v]http://www.fmod.org/forum/viewtopic.php?t=2794[/url:2olnwz4v]

That answers the muting part (use the DSP stuff). Looks like that guy had almost exactly the same question I had though.

  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.