0
0

Mp3 Player sample including WM_HOTKEY command (evc 4 fmodce.dll) for pocket pc
[url:aupns0on]http://www.geocities.com/takyonxxx/download/download.htm[/url:aupns0on]
[code:aupns0on]

include "stdafx.h"

include "resource.h"

include <windows.h>

include <aygshell.h>

include <winsock2.h>

include <bt_api.h>

include <windowsx.h>

include <commctrl.h>

include <stdio.h>

include <time.h>

include "Winuser.h"

include "fmod.h"

include "fmod_errors.h"

define MAX_LOADSTRING 100

define RECORDRATE 22050

define RECORDLEN (RECORDRATE * 100)

HINSTANCE g_hInst;
////////////variables////////////////////
HWND g_hwndCB; // The command bar handle
HANDLE hFind;
WIN32_FIND_DATA findData = {0};
static TCHAR NameLBSelect[256] = TEXT("");
static BOOL bPressed = FALSE;
TCHAR szOut[100];
TCHAR str1[256] = TEXT("");
TCHAR str2[256] = TEXT("");
TCHAR buf[MAX_PATH];
TCHAR path[MAX_PATH];
FSOUND_STREAM *stream = NULL;
HBRUSH g_hbrBackground = NULL;
DWORD indexLB,indexCount;
FSOUND_SAMPLE *samp = NULL;
UINT timerid = 0;
int channel = -1, retrycount = 0, streamchan = -1, nTimes = 1, i,echoid = -1, echoid2 = -1,flangeid = -1,liste=0;
int kontrol=0,ses = 52,stbt=0;
unsigned int lengthms, currtime;
FSOUND_STREAM *oldstream ;
long lRC;
HWND hList;
//////////////////

define REVERB_NUMTAPS 7

typedef struct
{
FSOUND_DSPUNIT Unit;
char *historybuff; /
storage space for tap history /
char *workarea; /
a place to hold 1 buffer worth of data (for preverb) /
int delayms; /
delay of p/reverb tab in milliseconds /
int volume; /
volume of p/reverb tab /
int pan; /
pan of p/reverb tab /
int historyoffset; /
running offset into history buffer /
int historylen; /
size of history buffer in SAMPLES */
} REVERBTAP;

define OUTPUT_RATE 44100

REVERBTAP DSP_ReverbTap[REVERB_NUMTAPS];
FSOUND_DSPUNIT *DrySFXUnit = NULL;
///////////////functions/////////////////
void LoadSong(HWND hDlg)
{
char s[MAX_PATH];
GetDlgItemText(hDlg, IDC_PATH, path, MAX_PATH);
wsprintf(str1, TEXT("%s%s%s"), path ,L"\",NameLBSelect );
WideCharToMultiByte(CP_ACP, 0, str1, -1, s, 256, NULL, NULL);
stream = NULL;
stream = FSOUND_Stream_Open(s, 0 , 0 , 0);
lstrcpy(path,L"");
lstrcpy(buf,L"");
lstrcpy(str1,L"");

}

//MessageBox(0, TEXT("YOK"), TEXT("Warning"), MB_OK);
void RegisterHotKeys(HWND hDlg)
{
::RegisterHotKey(hDlg, 0xC1, MOD_WIN , 0xC1);
::RegisterHotKey(hDlg, 0xC2, MOD_WIN , 0xC2);
::RegisterHotKey(hDlg, 0xC3, MOD_WIN , 0xC3);
::RegisterHotKey(hDlg, 0xC4, MOD_WIN , 0xC4);
::RegisterHotKey(hDlg, 0xC5, MOD_WIN , 0xC5);
}
void * F_CALLBACKAPI DSP_ReverbCallback(void *originalbuffer, void *newbuffer, int length, void *param)
{
int mixertype = FSOUND_GetMixer();
int count;
int bytesperoutputsample;
REVERBTAP *tap = (REVERBTAP *)param;
union sample
{
void *vptr;
signed int *dptr;
signed short *wptr;
float *fptr;
};

if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
{
    bytesperoutputsample = 4;   // 16bit stereo
}
else
{
    bytesperoutputsample = 8;   // 32bit stereo
}

// reverb history buffer is a ringbuffer.  If the length makes the copy wrap, then split the copy 
// into end part, and start part.. 
if (tap-&gt;historyoffset + length &gt; tap-&gt;historylen)
{
    int taillen = tap-&gt;historylen - tap-&gt;historyoffset;
    int startlen = length - taillen;

    // mix a scaled version of history buffer into output
    FSOUND_DSP_MixBuffers(newbuffer, tap-&gt;historybuff + (tap-&gt;historyoffset &lt;&lt; 2), taillen, OUTPUT_RATE, tap-&gt;volume, tap-&gt;pan, FSOUND_STEREO | FSOUND_16BITS);
    FSOUND_DSP_MixBuffers((char *)newbuffer+(taillen * bytesperoutputsample), tap-&gt;historybuff, startlen, OUTPUT_RATE, tap-&gt;volume, tap-&gt;pan, FSOUND_STEREO | FSOUND_16BITS);

    // now copy input into reverb/history buffer 
    {
        signed short *dest;
        union sample src;

        dest = (signed short *)(tap-&gt;historybuff + (tap-&gt;historyoffset &lt;&lt; 2));
        src.vptr = newbuffer;

        for (count=0; count &lt; taillen * 2; count++)
        {
            int val;

            if (mixertype == FSOUND_MIXER_QUALITY_FPU)
            {
                val = (int)src.fptr[count];
            }
            else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
            {
                val = (int)src.wptr[count];
            }
            else
            {
                val = (int)src.dptr[count];
            }               

            val = (val &gt; 32767 ? 32767 : val &lt; -32768 ? -32768 : val);
            dest[count] = val;
        }  
    }
    {
        signed short *dest;
        union sample src;

        dest = (signed short *)tap-&gt;historybuff;    // always 16bit
        src.vptr = (char *)newbuffer + (taillen * bytesperoutputsample);

        for (count=0; count &lt; startlen * 2; count++)
        {
            int val;

            if (mixertype == FSOUND_MIXER_QUALITY_FPU)
            {
                val = (int)src.fptr[count];
            }
            else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
            {
                val = (int)src.wptr[count];
            }
            else
            {
                val = (int)src.dptr[count];
            }               

            val = (val &gt; 32767 ? 32767 : val &lt; -32768 ? -32768 : val);
            dest[count] = val;
        }  
    }

}
// no wrapping reverb buffer, just write dest
else
{
    // mix a scaled version of history buffer into output
    FSOUND_DSP_MixBuffers(newbuffer, tap-&gt;historybuff + (tap-&gt;historyoffset &lt;&lt; 2), length, OUTPUT_RATE, tap-&gt;volume, tap-&gt;pan, FSOUND_STEREO | FSOUND_16BITS);

    // now copy input into reverb/history buffer 
    {
        signed short *dest;
        union sample src = { newbuffer };

        dest = (signed short *)(tap-&gt;historybuff + (tap-&gt;historyoffset &lt;&lt; 2));

        for (count=0; count &lt; length * 2; count++)
        {
            int val;

            if (mixertype == FSOUND_MIXER_QUALITY_FPU)
            {
                val = (int)src.fptr[count];
            }
            else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6)
            {
                val = (int)src.wptr[count];
            }
            else
            {
                val = (int)src.dptr[count];
            }               
            val = (val &gt; 32767 ? 32767 : val &lt; -32768 ? -32768 : val);
            dest[count] = val;
        }  
    }
}


tap-&gt;historyoffset += length;
if (tap-&gt;historyoffset &gt;= tap-&gt;historylen) 
{
    tap-&gt;historyoffset -= tap-&gt;historylen;
}

// reverb history has been mixed into new buffer, so return it.
return newbuffer;

}

void SetupReverb()
{
/*
REVERB SETUP
/
/
something to fiddle with. /
/
int delay[REVERB_NUMTAPS] = { 131, 149, 173, 211, 281, 401, 457}; /* prime numbers make it sound cool! */
int delay[REVERB_NUMTAPS] = { 0, 0, 0, 0 ,0, 0, 0};
int volume[REVERB_NUMTAPS] = { 120, 100, 95, 90, 80, 60, 50};
int pan[REVERB_NUMTAPS] = { 100, 128, 128, 152, 128, 100, 152};
int count;

for (count=0; count&lt; REVERB_NUMTAPS; count++)
{
    DSP_ReverbTap[count].delayms        = delay[count]; 
    DSP_ReverbTap[count].volume         = volume[count];
    DSP_ReverbTap[count].pan            = pan[count];
    DSP_ReverbTap[count].historyoffset  = 0;
    DSP_ReverbTap[count].historylen     = (DSP_ReverbTap[count].delayms * OUTPUT_RATE / 1000);
    if (DSP_ReverbTap[count].historylen &lt; FSOUND_DSP_GetBufferLength())
    {
        DSP_ReverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); /* just in case our calc is not the same. */
    }

    DSP_ReverbTap[count].historybuff    = (char *)malloc(DSP_ReverbTap[count].historylen * 4);  /* * 4 is for 16bit stereo (mmx only) */
    memset(DSP_ReverbTap[count].historybuff, 0, DSP_ReverbTap[count].historylen * 4);
    DSP_ReverbTap[count].workarea       = NULL;
    DSP_ReverbTap[count].Unit           = FSOUND_DSP_Create(&amp;DSP_ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+20+(count*2), &amp;DSP_ReverbTap[count]);

    FSOUND_DSP_SetActive(DSP_ReverbTap[count].Unit, TRUE);
}

}
void CloseReverb()
{
int count;

for (count=0; count&lt;REVERB_NUMTAPS; count++)
{
    FSOUND_DSP_Free(DSP_ReverbTap[count].Unit); 
    DSP_ReverbTap[count].Unit = NULL;

    free(DSP_ReverbTap[count].historybuff);     
    DSP_ReverbTap[count].historybuff = NULL;

    if (DSP_ReverbTap[count].workarea)
    {
        free(DSP_ReverbTap[count].workarea);        
        DSP_ReverbTap[count].workarea = NULL;
    }
}

}

LRESULT OnHotKey(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
int idHotKey = (int) wParam;
/* UINT fuModifiers = (UINT) LOWORD(lParam);
UINT uVirtKey = (UINT) HIWORD(lParam);
TCHAR szMessage[200];
_stprintf(szMessage, _T("WM_HOTKEY \r\n\tidHotKey: 0x%08x, \r\n\tfuModifiers: 0x%08x, \r\n\tuVirtKey: 0x%08x\r\n"), idHotKey, fuModifiers, uVirtKey);
MessageBox(0,szMessage , TEXT("Warning"), MB_OK);*/
switch (idHotKey)
{
case 0x000000c1 :
if(stbt==0){
if(ses>0 && ses!=0){
if(ses<33){ses=ses-4;}
else{ses=ses-16;}
if(ses<0){ses=0;}
FSOUND_SetVolume(streamchan, ses);}
}else{
currtime =FSOUND_Stream_GetTime(stream);
lengthms = FSOUND_Stream_GetLengthMs(stream);
if (currtime<lengthms & currtime>1000 ){
FSOUND_Stream_SetTime(stream, currtime-(int) 10000.0f);
}

    }
    break;
case 0x000000c2 :
     if(stbt==0){
    if(ses&lt;257 &amp;&amp; ses!=256){
        if(ses&lt;33){ses=ses+4;}
        else{ses=ses+16;}
    if(ses&gt;256){ses=256;}
    FSOUND_SetVolume(streamchan, ses);}
    }else{
            currtime =FSOUND_Stream_GetTime(stream);
            lengthms = FSOUND_Stream_GetLengthMs(stream);
            if (currtime&lt;lengthms &amp; currtime&gt;1000 ){
            FSOUND_Stream_SetTime(stream, currtime+(int) 10000.0f);
            }

    }
    break;
case 0x000000c3 :
    if(stbt==0){
    hList = GetDlgItem(hDlg, IDC_LIST);
    indexLB = SendMessage (hList,   LB_GETCURSEL, 0, 0);
    indexCount=SendMessage (hList,  LB_GETCOUNT, 0, 0);
    if(indexLB==0){
            SendMessage (hList,LB_GETTEXT, indexCount-1, (LPARAM)NameLBSelect);
                oldstream = stream;
                LoadSong(hDlg);
                FSOUND_Stream_Close(oldstream);
                streamchan = FSOUND_Stream_Play(FSOUND_FREE, stream);
                lRC= SendDlgItemMessage (hDlg, IDC_LIST,    LB_SETCURSEL , (WPARAM) indexCount-1,(LPARAM)  0);
                FSOUND_SetVolume(streamchan, ses);
    }
    else{
              SendMessage (hList,LB_GETTEXT, indexLB-1, (LPARAM)NameLBSelect);
                oldstream = stream;
                LoadSong(hDlg);
                FSOUND_Stream_Close(oldstream);
                streamchan = FSOUND_Stream_Play(FSOUND_FREE, stream);
                lRC= SendDlgItemMessage (hDlg, IDC_LIST,    LB_SETCURSEL , (WPARAM) indexLB-1,(LPARAM)  0);
                FSOUND_SetVolume(streamchan, ses);}
    }else{

                FSOUND_Record_StartSample(samp, FALSE);
    }
    return (0);
    break;
case 0x000000c4 :
    if(stbt==0){
    hList = GetDlgItem(hDlg, IDC_LIST);
    indexLB = SendMessage (hList,   LB_GETCURSEL, 0, 0);
    indexCount=SendMessage (hList,  LB_GETCOUNT, 0, 0);
    if(indexLB==indexCount-1){
            SendMessage (hList,LB_GETTEXT, 0, (LPARAM)NameLBSelect);
                oldstream = stream;
                LoadSong(hDlg);
                FSOUND_Stream_Close(oldstream);
                streamchan = FSOUND_Stream_Play(FSOUND_FREE, stream);
                lRC= SendDlgItemMessage (hDlg, IDC_LIST,    LB_SETCURSEL , (WPARAM) 0,(LPARAM)  0);
                FSOUND_SetVolume(streamchan, ses);
    }
    else{
    SendMessage (hList,LB_GETTEXT, indexLB+1, (LPARAM)NameLBSelect);
                oldstream = stream;
                LoadSong(hDlg);
                FSOUND_Stream_Close(oldstream);
                streamchan = FSOUND_Stream_Play(FSOUND_FREE, stream);
                lRC= SendDlgItemMessage (hDlg, IDC_LIST,    LB_SETCURSEL , (WPARAM) indexLB+1,(LPARAM)  0);
                FSOUND_SetVolume(streamchan, ses);}
        }else{

                FSOUND_Record_Stop();                   
                channel = FSOUND_PlaySound(FSOUND_FREE, samp);
                FSOUND_SetVolume(channel, ses);
    }
    return (0);
    break;
case 0x000000c5 :

          if(stbt==0)
          {
              stbt=1;}
          else if(stbt==1){
              stbt=0; }   
     break;
default:
    //MessageBox(0, TEXT(&quot;YOK&quot;), TEXT(&quot;Warning&quot;), MB_OK);
    break;
}
return 0;

}

BOOL WINAPI MainDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
g_hInst = hInstance;
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return msg.wParam;

}

BOOL WINAPI MainDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{

switch (msg)
{
case WM_INITDIALOG:
    {

        SHINITDLGINFO sid;
        SHMENUBARINFO mbi;
        RECT rc;

        sid.dwMask   = SHIDIM_FLAGS;
        sid.dwFlags = SHIDIF_SIZEDLGFULLSCREEN;
        sid.hDlg   = hDlg;

        memset(&amp;mbi, 0, sizeof(SHMENUBARINFO));
        mbi.cbSize     = sizeof(SHMENUBARINFO);
        mbi.hwndParent = hDlg;
        mbi.nToolBarId = IDR_MENU;
        mbi.hInstRes   = g_hInst;
        mbi.nBmpId     = 0;
        mbi.cBmpImages = 0;
        SHCreateMenuBar(&amp;mbi);
        // size the listbox control
        GetClientRect(hDlg, &amp;rc);
        RegisterHotKeys(hDlg);
        // Size the listbox control to the size of the window
        SetWindowPos(GetDlgItem(hDlg, IDC_LIST),0,0,25,241,245,0);

        timerid = SetTimer(hDlg, 1,100, 0L);
            if (!timerid)
            {   
                MessageBoxW(NULL, L&quot;Timer creation failed&quot;, L&quot;Error&quot;, MB_ICONHAND | MB_OK);
                DestroyWindow(hDlg);
                return FALSE;
            } 
        FSOUND_SetBufferSize(50);
        while (!FSOUND_Init(44100,2, FSOUND_INIT_GLOBALFOCUS) &amp;&amp; retrycount &lt; 10)
        {
            Sleep(100);
            retrycount++;
        }
        samp = FSOUND_Sample_Alloc(FSOUND_UNMANAGED, RECORDLEN, FSOUND_STEREO | FSOUND_16BITS , RECORDRATE, 255, 128, 255);
        g_hbrBackground = CreateSolidBrush(RGB(0,50,160));
        SetDlgItemText(hDlg, IDC_PATH, TEXT(&quot;\\Storage Card&quot;)); 
        SendMessage(GetDlgItem(hDlg,IDC_SLIDER1), TBM_SETRANGE, 0, MAKELPARAM(0, 256.0f));
        SendMessage(GetDlgItem(hDlg,IDC_SLIDER1), TBM_SETPOS, TRUE, 256.0f);
        liste=1;
        stbt=1;
    }
    break;
case WM_CTLCOLORDLG:    
        return (LONG)g_hbrBackground;
case WM_CTLCOLORSTATIC:
    {
        HDC hdcStatic = (HDC)wParam;
        SetTextColor(hdcStatic, RGB(255, 255, 255));
        SetBkMode(hdcStatic, TRANSPARENT);
        return (LONG)g_hbrBackground;
    }
    break;
case WM_HSCROLL:

        if ((HWND)lParam == GetDlgItem(hDlg, IDC_SLIDER1))
        {  
         FSOUND_SetVolume(streamchan, (int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0));
         ses=(int)SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
        }      
        break;        
case WM_HOTKEY:
    if(liste==1)
    {  
        OnHotKey(hDlg, wParam, lParam);           
    }
        break;      
case WM_TIMER:
    {      SendMessage(GetDlgItem(hDlg,IDC_SLIDER1), TBM_SETPOS, TRUE, (WPARAM) ses);
            currtime =FSOUND_Stream_GetTime(stream);
            lengthms = FSOUND_Stream_GetLengthMs(stream);
            SetDlgItemInt(hDlg, IDC_TTIME,lengthms/1000,FALSE);
            SetDlgItemInt(hDlg, IDC_CTIME,currtime/1000,FALSE);
            if (currtime/1000 == lengthms/1000-1)
             {  hList = GetDlgItem(hDlg, IDC_LIST);
                indexLB = SendMessage (hList,   LB_GETCURSEL, 0, 0);
                indexCount=SendMessage (hList,  LB_GETCOUNT, 0, 0);
                if(indexLB==indexCount-1)
                {
                SendDlgItemMessage (hDlg, IDC_LIST, LB_SETCURSEL , 0, 0);
                }

                SendMessage (hList,LB_GETTEXT, indexLB+1, (LPARAM)NameLBSelect);
                        oldstream = stream;
                        LoadSong(hDlg);
                        FSOUND_Stream_Close(oldstream);
                streamchan = FSOUND_Stream_Play(FSOUND_FREE, stream);
                SendDlgItemMessage (hDlg, IDC_LIST, LB_SETCURSEL , indexLB+1, 0);
            }
    }
          break;
    case WM_CLOSE:
    case WM_DESTROY:
            FSOUND_DSP_Free(DrySFXUnit);
            CloseReverb();
            FSOUND_Sample_Free(samp);
            FSOUND_Stream_Close(stream);
            FSOUND_Close();
            KillTimer(hDlg, timerid);
            PostQuitMessage(0);
            return TRUE;
        break;              
case WM_COMMAND:

    switch(LOWORD(wParam))
    {
     case IDC_LIST:
                switch(HIWORD(wParam))
                {
                    case LBN_SELCHANGE:
                    {
                        hList = GetDlgItem(hDlg, IDC_LIST);
                        indexLB = SendMessage (hList,   LB_GETCURSEL, 0, 0);
                        SendMessage (hList,LB_GETTEXT, indexLB, (LPARAM)NameLBSelect);
                            //FSOUND_STREAM *oldstream = stream;
                            oldstream = stream;
                            LoadSong(hDlg);
                            FSOUND_Stream_Close(oldstream);
                            streamchan = FSOUND_Stream_Play(FSOUND_FREE, stream);
                            FSOUND_SetVolume(streamchan, ses);
                            liste=1;
                     }
                    break;
                }
        break;
        case ID_ADD_DIR:
            char sfile[260];
            stbt=0;
            GetDlgItemText(hDlg, IDC_PATH, path, MAX_PATH);
            wsprintf(str2, TEXT(&quot;%s%s&quot;), path ,L&quot;\\*.mp3&quot; );
            hFind = FindFirstFile (str2, &amp;findData);
            if (hFind == INVALID_HANDLE_VALUE)
                MessageBox (hDlg, L&quot;There is no mp3!.&quot;, NULL, MB_OK);
                else
                {
                do
                {                          
                    int index = SendDlgItemMessage(hDlg, IDC_LIST, LB_ADDSTRING, 0, (LPARAM)findData.cFileName);
                    SendDlgItemMessage(hDlg, IDC_LIST, LB_SETITEMDATA, (WPARAM)index, (LPARAM)nTimes);

                }
                while (FindNextFile(hFind, &amp;findData));
                CloseHandle (hFind);
                lstrcpy(path,L&quot;&quot;);
                lstrcpy(str2,L&quot;&quot;);
                liste=1;
                }              
        break;
        case IDM_CLEAR:
                stbt=1;
                FSOUND_Stream_Close(stream);
                SendDlgItemMessage(hDlg, IDC_LIST, LB_RESETCONTENT, 0, 0);
                SetDlgItemText(hDlg, IDC_PATH, TEXT(&quot;\\Storage Card&quot;));
                //liste=0;
            break;
        case ID_PLAY_PAUSE:
                FSOUND_SetPaused(streamchan, !FSOUND_GetPaused(streamchan));
                break;
        case DSP:
            if (DrySFXUnit==NULL)
            {
            SetupReverb();
            DrySFXUnit = FSOUND_DSP_Create(NULL, FSOUND_DSP_DEFAULTPRIORITY_USER+100, 0);
            FSOUND_DSP_SetActive(DrySFXUnit, TRUE);
            }
            else if(DrySFXUnit)
            {
            FSOUND_DSP_Free(DrySFXUnit);
            CloseReverb();
            FSOUND_DSP_SetActive(DrySFXUnit, FALSE);
            DrySFXUnit = NULL;
            }
            return TRUE;

        case ID_QUIT:
            DestroyWindow(hDlg);
                break;
    }

break;
}

return 0;

}

[/code:aupns0on]

  • You must to post comments
Showing 0 results
Your Answer

Please first to submit.