home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 November / CDVD1105.ISO / Software / Freeware / programare / bass / c / custloop / custloop.c next >
Encoding:
C/C++ Source or Header  |  2005-09-21  |  7.0 KB  |  241 lines

  1. // BASS custom looping example, copyright (c) 2004-2005 Ian Luck.
  2.  
  3. #include <windows.h>
  4. #include <stdio.h>
  5. #include <process.h>
  6. #include "bass.h"
  7.  
  8. #define WIDTH 600    // display width
  9. #define HEIGHT 201    // height (odd number for centre line)
  10.  
  11. HWND win=NULL;
  12. DWORD scanthread=0;
  13. BOOL killscan=FALSE;
  14.  
  15. DWORD chan;
  16. DWORD bpp;            // bytes per pixel
  17. QWORD loop[2]={0};    // loop start & end
  18. HSYNC lsync;        // looping sync
  19.  
  20. HDC wavedc=0;
  21. HBITMAP wavebmp=0;
  22. BYTE *wavebuf;
  23.  
  24. /* display error messages */
  25. void Error(char *es)
  26. {
  27.     char mes[200];
  28.     sprintf(mes,"%s\n(error code: %d)",es,BASS_ErrorGetCode());
  29.     MessageBox(win,mes,"Error",0);
  30. }
  31.  
  32. void CALLBACK LoopSyncProc(HSYNC handle,DWORD channel,DWORD data,DWORD user)
  33. {
  34.     if (!BASS_ChannelSetPosition(channel,loop[0])) // try seeking to loop start
  35.         BASS_ChannelSetPosition(channel,0); // failed, go to start of file instead
  36. }
  37.  
  38. void SetLoopStart(QWORD pos)
  39. {
  40.     loop[0]=pos;
  41. }
  42.  
  43. void SetLoopEnd(QWORD pos)
  44. {
  45.     loop[1]=pos;
  46.     BASS_ChannelRemoveSync(chan,lsync); // remove old sync
  47.     lsync=BASS_ChannelSetSync(chan,BASS_SYNC_POS|BASS_SYNC_MIXTIME,loop[1],LoopSyncProc,0); // set new sync
  48. }
  49.  
  50. /* scan the peaks */
  51. void __cdecl ScanPeaks(DWORD decoder)
  52. {
  53.     DWORD cpos=0,peak[2]={0};
  54.     while (!killscan) {
  55.         DWORD level=BASS_ChannelGetLevel(decoder); // scan peaks
  56.         DWORD pos=BASS_ChannelGetPosition(decoder)/bpp;
  57.         if (peak[0]<LOWORD(level)) peak[0]=LOWORD(level); // set left peak
  58.         if (peak[1]<HIWORD(level)) peak[1]=HIWORD(level); // set right peak
  59.         if (!BASS_ChannelIsActive(decoder)) pos=-1; // reached the end
  60.         else pos=BASS_ChannelGetPosition(decoder)/bpp;
  61.         if (pos>cpos) {
  62.             DWORD a;
  63.             for (a=0;a<peak[0]*(HEIGHT/2)/32768;a++)
  64.                 wavebuf[(HEIGHT/2-1-a)*WIDTH+cpos]=1+a; // draw left peak
  65.             for (a=0;a<peak[1]*(HEIGHT/2)/32768;a++)
  66.                 wavebuf[(HEIGHT/2+1+a)*WIDTH+cpos]=1+a; // draw right peak
  67.             if (pos>=WIDTH) break; // gone off end of display
  68.             cpos=pos;
  69.             peak[0]=peak[1]=0;
  70.         }
  71.     }
  72.     BASS_StreamFree(decoder); // free the decoder
  73.     scanthread=0;
  74. }
  75.  
  76. /* select a file to play, and start scanning it */
  77. BOOL PlayFile()
  78. {
  79.     char file[MAX_PATH]="";
  80.     OPENFILENAME ofn={0};
  81.     ofn.lStructSize=sizeof(ofn);
  82.     ofn.hwndOwner=win;
  83.     ofn.nMaxFile=MAX_PATH;
  84.     ofn.lpstrFile=file;
  85.     ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER;
  86.     ofn.lpstrTitle="Select a file to play";
  87.     ofn.lpstrFilter="Playable files\0*.mp3;*.mp2;*.mp1;*.ogg;*.wav;*.aif;*.mo3;*.it;*.xm;*.s3m;*.mtm;*.mod;*.umx\0All files\0*.*\0\0";
  88.     if (!GetOpenFileName(&ofn)) return FALSE;
  89.  
  90.     if (!(chan=BASS_StreamCreateFile(FALSE,file,0,0,0))
  91.         && !(chan=BASS_MusicLoad(FALSE,file,0,0,BASS_MUSIC_RAMPS|BASS_MUSIC_POSRESET|BASS_MUSIC_PRESCAN,0))) {
  92.         Error("Can't play file");
  93.         return FALSE; // Can't load the file
  94.     }
  95.     {
  96.         BYTE data[2000]={0};
  97.         BITMAPINFOHEADER *bh=(BITMAPINFOHEADER*)data;
  98.         RGBQUAD *pal=(RGBQUAD*)(data+sizeof(*bh));
  99.         int a;
  100.         bh->biSize=sizeof(*bh);
  101.         bh->biWidth=WIDTH;
  102.         bh->biHeight=-HEIGHT;
  103.         bh->biPlanes=1;
  104.         bh->biBitCount=8;
  105.         bh->biClrUsed=bh->biClrImportant=HEIGHT/2+1;
  106.         // setup palette
  107.         for (a=1;a<=HEIGHT/2;a++) {
  108.             pal[a].rgbRed=(255*a)/(HEIGHT/2);
  109.             pal[a].rgbGreen=255-pal[a].rgbRed;
  110.         }
  111.         // create the bitmap
  112.         wavebmp=CreateDIBSection(0,(BITMAPINFO*)bh,DIB_RGB_COLORS,&wavebuf,NULL,0);
  113.         wavedc=CreateCompatibleDC(0);
  114.         SelectObject(wavedc,wavebmp);
  115.     }
  116.     bpp=BASS_ChannelGetLength(chan)/WIDTH; // bytes per pixel
  117.     if (bpp<BASS_ChannelSeconds2Bytes(chan,0.02)) // minimum 20ms per pixel (BASS_ChannelGetLevel scans 20ms)
  118.         bpp=BASS_ChannelSeconds2Bytes(chan,0.02);
  119.     BASS_ChannelSetSync(chan,BASS_SYNC_END|BASS_SYNC_MIXTIME,0,LoopSyncProc,0); // set sync to loop at end
  120.     BASS_ChannelPlay(chan,FALSE); // start playing
  121.     {
  122.         DWORD chan2=BASS_StreamCreateFile(FALSE,file,0,0,BASS_STREAM_DECODE);
  123.         if (!chan2) chan2=BASS_MusicLoad(FALSE,file,0,0,BASS_MUSIC_DECODE,0);
  124.         scanthread=_beginthread(ScanPeaks,0,chan2); // start scanning peaks in a new thread
  125.     }
  126.     return TRUE;
  127. }
  128.  
  129. void DrawTimeLine(HDC dc, QWORD pos, DWORD col, DWORD y)
  130. {
  131.     HPEN pen=CreatePen(PS_SOLID,0,col),oldpen;
  132.     DWORD wpos=pos/bpp;
  133.     DWORD time=BASS_ChannelBytes2Seconds(chan,pos);
  134.     char text[10];
  135.     sprintf(text,"%u:%02u",time/60,time%60);
  136.     oldpen=SelectObject(dc,pen);
  137.     MoveToEx(dc,wpos,0,NULL);
  138.     LineTo(dc,wpos,HEIGHT);
  139.     SetTextColor(dc,col);
  140.     SetBkMode(dc,TRANSPARENT);
  141.     SetTextAlign(dc,wpos>=WIDTH/2?TA_RIGHT:TA_LEFT);
  142.     TextOut(dc,wpos,y,text,strlen(text));
  143.     SelectObject(dc,oldpen);
  144.     DeleteObject(pen);
  145. }
  146.  
  147. /* window procedure */
  148. long FAR PASCAL SpectrumWindowProc(HWND h, UINT m, WPARAM w, LPARAM l)
  149. {
  150.     switch (m) {
  151.         case WM_LBUTTONDOWN: // set loop start
  152.             SetLoopStart(LOWORD(l)*bpp);
  153.             return 0;
  154.         case WM_RBUTTONDOWN: // set loop end
  155.             SetLoopEnd(LOWORD(l)*bpp);
  156.             return 0;
  157.         case WM_MOUSEMOVE:
  158.             if (w&MK_LBUTTON) SetLoopStart(LOWORD(l)*bpp);
  159.             if (w&MK_RBUTTON) SetLoopEnd(LOWORD(l)*bpp);
  160.             return 0;
  161.  
  162.         case WM_TIMER:
  163.             InvalidateRect(h,0,0); // refresh window
  164.             return 0;
  165.         case WM_PAINT:
  166.             if (GetUpdateRect(h,0,0)) {
  167.                 PAINTSTRUCT p;
  168.                 HDC dc;
  169.                 if (!(dc=BeginPaint(h,&p))) return 0;
  170.                 BitBlt(dc,0,0,WIDTH,HEIGHT,wavedc,0,0,SRCCOPY); // draw peak waveform
  171.                 DrawTimeLine(dc,loop[0],0xffff00,12); // loop start
  172.                 DrawTimeLine(dc,loop[1],0x00ffff,24); // loop end
  173.                 DrawTimeLine(dc,BASS_ChannelGetPosition(chan),0xffffff,0); // current pos
  174.                 EndPaint(h,&p);
  175.             }
  176.             return 0;
  177.  
  178.         case WM_CREATE:
  179.             win=h;
  180.             // initialize BASS
  181.             if (!BASS_Init(-1,44100,0,win,NULL)) {
  182.                 Error("Can't initialize device");
  183.                 return -1;
  184.             }
  185.             if (!PlayFile()) { // start a file playing
  186.                 BASS_Free();
  187.                 return -1;
  188.             }
  189.             SetTimer(h,0,100,0); // set update timer (10hz)
  190.             break;
  191.  
  192.         case WM_DESTROY:
  193.             KillTimer(h,0);
  194.             if (scanthread) { // still scanning
  195.                 killscan=TRUE;
  196.                 WaitForSingleObject(scanthread,1000); // wait for the thread
  197.             }
  198.             BASS_Free();
  199.             if (wavedc) DeleteDC(wavedc);
  200.             if (wavebmp) DeleteObject(wavebmp);
  201.             PostQuitMessage(0);
  202.             break;
  203.     }
  204.     return DefWindowProc(h, m, w, l);
  205. }
  206.  
  207. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
  208. {
  209.     WNDCLASS wc={0};
  210.     MSG msg;
  211.  
  212.     // check that BASS 2.2 was loaded
  213.     if (BASS_GetVersion()!=MAKELONG(2,2)) {
  214.         MessageBox(0,"BASS version 2.2 was not loaded","Incorrect BASS.DLL",0);
  215.         return 0;
  216.     }
  217.  
  218.     // register window class and create the window
  219.     wc.lpfnWndProc = SpectrumWindowProc;
  220.     wc.hInstance = hInstance;
  221.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  222.     wc.lpszClassName = "BASS-CustLoop";
  223.     if (!RegisterClass(&wc) || !CreateWindow("BASS-CustLoop",
  224.             "BASS custom looping example (left-click to set loop start, right-click to set end)",
  225.             WS_POPUPWINDOW|WS_CAPTION|WS_VISIBLE, 100, 100,
  226.             WIDTH+2*GetSystemMetrics(SM_CXDLGFRAME),
  227.             HEIGHT+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYDLGFRAME),
  228.             NULL, NULL, hInstance, NULL)) {
  229.         Error("Can't create window");
  230.         return 0;
  231.     }
  232.     ShowWindow(win, SW_SHOWNORMAL);
  233.  
  234.     while (GetMessage(&msg,NULL,0,0)>0) {
  235.         TranslateMessage(&msg);
  236.         DispatchMessage(&msg);
  237.     }
  238.  
  239.     return 0;
  240. }
  241.