- 음악과 나 -/『 짬 통 』

저수준제어를 이용한 wave재생 - 소스 , wavescope

noon2dy 2006. 5. 18. 02:45

 

 

 

2002-08-22 오후 3:33:02   /  번호: 5029  / 평점:  (9.0) category: Sound  /  조회: 4,208 
 [API] 저수준 제어를 이용한 WAVE 재생 - 소스공개 트론의 유령 / lovesgh  
트론의 유령님께 메시지 보내기  트론의 유령님을 내 주소록에 추가합니다.  트론의 유령님의 블로그가 없습니다  

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- 프로그래밍에 사용 할 헤더 파일들 선언                         ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

#include

#include

#include

#include

#include "resource.h"

 

 

//-- WAVEFORMATEXTENSIBLE 에서 필요한 헤더 파일들 선언

#include

#include

#include

#include

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--  Global variable 선언 부분                              시작--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

//-- WndProc 및 외부 변수 선언

TCHAR szAppName[] = TEXT ("WAVE WIZARD V0.47a23");

HINSTANCE g_hInst;

 

 

//-- 파일 처리(읽기)

OPENFILENAME OFN ;

char caFileName [MAX_PATH] = " " ;

 

 

//-- Wave 처리용

static HWAVEOUT hWaveOut ;

 

WAVEFORMATEXTENSIBLE  waveFormatEx;

MMCKINFO mmCkInfoRIFF;

MMCKINFO mmCkInfoChunk;

HMMIO hMMIO;

DWORD waveSize; //-- Chunk header를 뺀 WaveData의 총 길이

 

 

//-- char ayyray  

char ca_wFormatTag  [50] ;

char ca_nChannels   [50] ;

char ca_nSamplesPerSec  [50] ;

char ca_nAvgBytesPerSec [50] ;

char ca_nBlockAlign [50] ;

char ca_wBitsPerSample  [50] ;

char ca_cbSize      [50] ;

char ca_lpstrFile   [40] ; // File Location..

 

 

//--수직 TrackBar

int xPos  = 0 ;

int xInc  = 0 ;

int xMax  = 1024 ;

char ca_xPos[10] ;

 

 

 

static BOOL bRecording, bReverse, bPlaying, bPaused, bEnding,

            bTerminating, bMute ;

 

static DWORD dwDataLength ;

static TCHAR szOpenError[] = TEXT ("Error opening waveform audio!");

static TCHAR szMemError [] = TEXT ("Error allocating memory!") ;

 

 

const int BufferNum = 6; //-- 버퍼의 갯수

 

//-- Wave 재생시 Double Buffering구현을 위한 버퍼

static PBYTE    pBuffer[6] ;

static PWAVEHDR pWaveHdr[6] ;

 

//-- mmioRead 에서 파일 끝인지 아닌지 리턴값 저장   

LONG mRet;

 

//-- Wave파일에서  버퍼마다 한번에 읽어 들일 크기

LONG read_size;

 

//-- 현재 MM_WOM_DONE : 진행상황 표시할때 쓸 변수

LONG CNT=0;

char ca_CNTNUM[100];

 

 

//-- SineWave 좌/우 최대값 저장

LONG maxL, maxR;

char L_MAX[10];

char R_MAX[10];

 

    

//-- 컬러 저장할 Color 선언 ( 초기화 - 파란색 )

COLORREF Color=RGB(200,255,255);

 

 

//-- 시간 관련

static HANDLE hTimer ;

SYSTEMTIME st ;

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--  Global variable 선언 부분                                끝--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int GET_READ_CHUNK ( OPENFILENAME OFN )                       ||

//_________________________________________________________________||

//                                                                 ||

//-- OPENFILENAME OFN - OFN.lpstrFile 로 전달 받은 파일의 위치에서 ||

//                      WAVE 파일의 Chunk 헤더를 읽는다            ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int GET_READ_CHUNK ( OPENFILENAME OFN )

{

    // Open the wave file.

    hMMIO = mmioOpen(OFN.lpstrFile, NULL, MMIO_READ | MMIO_ALLOCBUF) ;

    if (hMMIO == NULL)  

        return FALSE ;

    

    // Descend into the RIFF chunk.

    mmCkInfoRIFF.fccType = mmioFOURCC ('W', 'A', 'V', 'E') ;

    if (mmioDescend(hMMIO, &mmCkInfoRIFF, NULL, MMIO_FINDRIFF) != MMSYSERR_NOERROR)

        return FALSE ;

    

    // Descend into the format chunk.

    mmCkInfoChunk.ckid = mmioFOURCC ('f', 'm', 't', ' ') ;  

    if (mmioDescend(hMMIO, &mmCkInfoChunk, &mmCkInfoRIFF, MMIO_FINDCHUNK)

        != MMSYSERR_NOERROR)

        return FALSE ;

                    

    // Read the format information into the WAVEFORMATEX structure.

    if (mmioRead ( hMMIO, (char *)&waveFormatEx, sizeof(WAVEFORMATEXTENSIBLE) ) == -1)

        return FALSE ;

    

    // Ascend out of the format chunk.

    if (mmioAscend(hMMIO, &mmCkInfoChunk, 0) != MMSYSERR_NOERROR)

        return FALSE ;

    

    // Descend into the data chunk.

    mmCkInfoChunk.ckid = mmioFOURCC ('d', 'a', 't', 'a') ;

    if (mmioDescend(hMMIO, &mmCkInfoChunk, &mmCkInfoRIFF, MMIO_FINDCHUNK)

        != MMSYSERR_NOERROR)

        return FALSE ;

    

    // WAV 데이터의 크기를 저장해둔다.

    waveSize = mmCkInfoChunk.cksize ;

 

    return TRUE ;

}

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  static cxClient, cyClient ;                                    ||

//  BOOL WM_SIZE_FUNCTION ( LPARAM lParam )                        ||

//_________________________________________________________________||

//                                                                 ||

//  WM_SIZE : 윈도우 사이즈 크기가 바뀔때마다 크기정보를 얻는다.   ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

static cxClient, cyClient ;

BOOL WM_SIZE_FUNCTION ( LPARAM lParam )

{

    //static cxClient, cyClient ; // WM_PAINT 때문에 전역으로 빼돌림

 

    cxClient = LOWORD ( lParam ) ;

    cyClient = HIWORD ( lParam ) ;

 

    return TRUE ;

}

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                         시작--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int PLAY_BEG ( HWAVEOUT hWaveOut )                            ||

//_________________________________________________________________||

//                                                                 ||

//-- 재생 시작 기능                                                ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int PLAY_BEG ( )

{   

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int PLAY_PAUSE ( HWAVEOUT hWaveOut )                          ||

//_________________________________________________________________||

//                                                                 ||

//-- 재생 중 잠시 멈춤 기능                                        ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int PLAY_PAUSE ( HWAVEOUT hWaveOut )

{

    // Pause or restart output          

    if ( !bPaused )

    {

        waveOutPause ( hWaveOut ) ;

        bPaused = TRUE ;

    }

    else if ( bPaused )

    {

        waveOutRestart ( hWaveOut ) ;

        bPaused = FALSE ;

        //MessageBox(hwnd, "bPaused = FALSE", "Message", MB_OK );

    }

    

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int PLAY_END ( HWAVEOUT hWaveOut )                            ||

//_________________________________________________________________||

//                                                                 ||

//-- 재생 중지                                                     ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int PLAY_END ( HWAVEOUT hWaveOut )

{

    waveOutReset ( hWaveOut ) ;

    waveOutClose ( hWaveOut ) ;

 

    bEnding = TRUE ;

 

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int IDC_SET_MUTE_FUNCTION ( HWAVEOUT hWaveOut )               ||

//_________________________________________________________________||

//                                                                 ||

//-- 음소거                                                        ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int IDC_SET_MUTE_FUNCTION ( HWAVEOUT hWaveOut )

{

    if (!bMute)

    {

        waveOutSetVolume( hWaveOut, 0x00000000);

        bMute = TRUE ;

    }

    else

    {

        waveOutSetVolume( hWaveOut, 0xFFFFFFFF);

        bMute = FALSE ;

    }

    return TRUE ;

}

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                           끝--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- BOOL WAVE_BIT_CHECK ()                                        ||

//_________________________________________________________________||

//                                                                 ||

//-- 20 Bit 인지 24 Bit 인지 판별해 낸다.                          ||

//-- 전역 waveFormatEx 를 사용하므로 인자는 없다.                  ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

BOOL WAVE_BIT_CHECK ()

{

    //-- 20 Bit 재생

    if ( waveFormatEx.Format.wBitsPerSample == 20 )

    {

        waveFormatEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;

        waveFormatEx.Format.wBitsPerSample = 24;  

        waveFormatEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

        

        wsprintf ( ca_wBitsPerSample, "%d" , 20 );

    }

 

    //-- 24 Bit 재생        

    if ( waveFormatEx.Format.wBitsPerSample == 24 )

    {

        waveFormatEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;

        waveFormatEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

        //wsprintf(caBit, "%d", waveFormatEx.Format.wBitsPerSample );

        waveFormatEx.dwChannelMask = SPEAKER_FRONT_LEFT |

                         SPEAKER_FRONT_RIGHT ;

    }

    return TRUE ;

}

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                         시작--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  void GET_PEAK_MAX ( int bit, int isMonoStereo, void *buf,      ||

//                      int bufsize, int *maxL, int *maxR )        ||

//_________________________________________________________________||

//                                                                 ||

//--MM_WOM_DONE에서 호출                                           ||

//                                                                 ||

//--현재 재생중인 사운드 Buffer의 좌/우 MAX 치를 구한다.           ||                                                       ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void GET_PEAK_MAX (int bit,int isMonoStereo, void *buf, LONG bufsize,

                   LONG *maxL, LONG *maxR )

{

    

    //TODO:

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL GET_SINE_WAVE ( int bit,                                  ||

//                       int isMonoStereo,                         ||

//                       void *buf,                                ||

//                       LONG bufsize )                            ||

//_________________________________________________________________||

//                                                                 ||

//--MM_WOM_DONE_FUNCTION에서 호출                                  ||

//                                                                 ||

//--넘겨 받은 버퍼의 내용 -> 수치화된 값 조사                      ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

#define NUM 1024

 

long ia_L_MAX[NUM] ;

long ia_R_MAX[NUM] ;

 

BOOL GET_SINE_WAVE ( int bit,int isMonoStereo,void *buf,LONG bufsize)

{

    BYTE  *pB ; // 1 Byte (BYTE)                

    short *pW ; // 2 Byte (WORD)  

 

    LONG i;

 

    LONG cnt = bufsize / ( bit / 8 ) ; // 8:1, 16:2, 24:3, 32:4

    

    cnt /= isMonoStereo ;

 

    //-- 8 Bit

    if ( bit == 8 )

    {

        pB = ( BYTE * ) buf ;

 

        if ( isMonoStereo == 1 ) //-- Mono

        {

            for ( i = 0; i < NUM; i++ )

            {                                       

                ia_L_MAX[i] = (int) *pB / 2 ;

 

                pB ++ ;

            }

        }

 

        if ( isMonoStereo == 2 ) //-- Stereo

        {

            for ( i = 0; i < NUM; i++ )

            {                                       

                ia_L_MAX[i] = (int) *pB / 2 ;

                ia_R_MAX[i] = (int) *( pB + 1 ) / 2 ;

            

                pB += 2 ;           

            }

 

        }

    }

 

    //-- 16 Bit

    if ( bit == 16 )

    {

        pW = ( short * ) buf ;

 

        if ( isMonoStereo == 1 ) //-- Mono

        {

            for ( i = 0; i < NUM; i++ )

            {                                       

                ia_L_MAX[i] = (int) *pW / 0xff ;

 

                pW ++ ;

            }

        }

 

        if ( isMonoStereo == 2 ) //-- Stereo

        {

            for ( i = 0; i < NUM; i++ )

            {                                       

                ia_L_MAX[i] = (int) *pW / 0xff ;

                ia_R_MAX[i] = (int) *( pW + 1 ) / 0xff / 3 ;

            

                pW += 2 ;           

            }

        }

    }

 

    return TRUE ;

}

 

 

    

 

//-- Memory DC 설정

HDC MemDC ; 

HBITMAP OldBitMap ;

HBITMAP MemBit ;

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL DRAW_HORIZONTAL_LINE ( HWND hwnd, HDC hdc )               ||

//_________________________________________________________________||

//                                                                 ||

//  WM_PAINT 에서 호출 : 바탕화면에 수평으로 선을 그린다.          ||

//                                                                 ||

//  빠른 화면 갱신을 위해 MemoryDC 를 사용한다.                    ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

BOOL DRAW_HORIZONTAL_LINE ( HWND hwnd, HDC hdc )

{

    HPEN hpen, OldPen ;

    

    //-- 한 가운데

    hpen = CreatePen ( PS_DOT, 2, RGB ( 0, 0, 255 ) ) ;

    OldPen = ( HPEN ) SelectObject ( MemDC, hpen ) ;

 

    MoveToEx ( MemDC, 0, cyClient / 2, NULL ) ;

    LineTo   ( MemDC, cxClient, cyClient / 2 ) ;

 

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

 

    //-- [ L ] 채널

    hpen = CreatePen ( PS_SOLID, 1, RGB ( 255, 255, 255 ) ) ;

    OldPen =( HPEN ) SelectObject ( MemDC, hpen ) ;

 

    MoveToEx ( MemDC, 0, cyClient / 4, NULL ) ;  // 2/4

    LineTo   ( MemDC, cxClient, cyClient / 4 ) ; // 2/4

 

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

    //-- PS_DOT가 제대로 나오게 하기 위해 사용

    SetBkColor( MemDC, RGB(0,0,0) );

    hpen = CreatePen ( PS_DOT, 1, RGB ( 255, 255, 255 ) ) ;

    OldPen =( HPEN ) SelectObject ( MemDC, hpen ) ;

 

    MoveToEx ( MemDC, 0, cyClient / 8, NULL ) ;  // 1/4

    LineTo   ( MemDC, cxClient, cyClient / 8 ) ; // 1/4

 

    MoveToEx ( MemDC, 0, ( cyClient / 8 ) + ( cyClient / 4 ), NULL ) ;  // 3/4

    LineTo   ( MemDC, cxClient, ( cyClient / 8 ) + ( cyClient / 4 ) ) ; // 3/4

 

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

 

    //-- [ R ] 채널

    hpen = CreatePen ( PS_SOLID, 1, RGB ( 255, 255, 255 ) ) ;

    OldPen =( HPEN ) SelectObject ( MemDC, hpen ) ;

 

    MoveToEx ( MemDC, 0, ( cyClient / 2 ) + ( cyClient / 4 ), NULL ) ; // 2/4

    LineTo   ( MemDC, cxClient, ( cyClient / 2 ) + ( cyClient / 4 ) ) ; // 2/4

    

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

    //-- PS_DOT가 제대로 나오게 하기 위해 사용

    SetBkColor( MemDC, RGB(0,0,0) );

    hpen = CreatePen ( PS_DOT, 1, RGB ( 255, 255, 255 ) ) ;

    OldPen =( HPEN ) SelectObject ( MemDC, hpen ) ;

 

    MoveToEx ( MemDC, 0, ( cyClient / 2 ) + ( cyClient / 8 ), NULL ) ; // 1/4

    LineTo   ( MemDC, cxClient, ( cyClient / 2 ) + (cyClient / 8 ) ) ; // 1/4

 

    MoveToEx ( MemDC, 0, ( cyClient / 2 ) + ( cyClient / 8 ) + ( cyClient / 4 ) , NULL ) ; // 3/4

    LineTo   ( MemDC, cxClient, ( cyClient / 2 ) + ( cyClient / 8 ) + ( cyClient / 4 ) ) ; // 3/4

 

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL DRAW_SINE_WAVE ( HWND hwnd )                              ||

//_________________________________________________________________||

//                                                                 ||

//--WM_PAINT : WM_PAINT에서 호출                                   ||

//                                                                 ||

//--사인파형으로 그래프를 그린다.                                  ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

#define TWOPI  (2 * 3.14159)

BOOL DRAW_SINE_WAVE ( HWND hwnd , HDC hdc, int iBitsPerSample, int iChannels )

//BOOL DRAW_SINE_WAVE ( HWND hwnd , int iBitsPerSample, int iChannels )

{       

    // 이미 비트맵이 만들어져 있으면 지운다.

    if (MemBit)

        DeleteObject(MemBit);

 

    MemBit = CreateCompatibleBitmap ( hdc, 1600, 1200) ;

    MemDC = CreateCompatibleDC ( hdc ) ;

    OldBitMap = ( HBITMAP ) SelectObject ( MemDC, MemBit ) ;

 

    //-- Wave 의 색깔 지정

    HPEN hpen, OldPen ;

    //hpen = CreatePen ( PS_SOLID, 1, RGB ( 0, 0, 255 ) ) ; 

    hpen = CreatePen ( PS_SOLID, 1, Color ) ;

    OldPen =( HPEN ) SelectObject ( MemDC, hpen ) ;

    

 

    POINT L_Point[NUM], R_Point[NUM] ;

 

 

    //- [L] Chnnel

    for ( long iCnt = 0 ; iCnt < NUM; iCnt++ )

    {

        L_Point[iCnt].x = iCnt * cxClient / NUM ;

        

        //-- 8 Bit

        if ( iBitsPerSample == 8  )

        {

            L_Point[iCnt].y = (int) ( ( cyClient / 6 ) + ( cyClient / 4 ) * (1 - sin (TWOPI * ia_L_MAX[iCnt] / NUM ) * 2 )) ;

        }       

        

        //-- 16Bit

        if ( iBitsPerSample == 16 )

        {

            L_Point[iCnt].y = (int) ( ( cyClient / 4 ) * (1 - sin (TWOPI * ia_L_MAX[iCnt] / NUM))) ;

        }

    }

    Polyline ( MemDC, L_Point, NUM );   

 

 

    //-- Stereo 일때만 오른쪽 채널도 표시

    if ( iChannels == 2 )

    {

        //- [R] Chnnel

        for ( long iCnt = 0 ; iCnt < NUM; iCnt++ )

        {

            R_Point[iCnt].x =  iCnt * cxClient / NUM ;  

            

            //-- 8 Bit

            if ( iBitsPerSample == 8  )

            {

                R_Point[iCnt].y = (int) ( ( cyClient / 6 ) + ( cyClient / 2 ) + ( cyClient / 4 ) * (1 - sin (TWOPI * ia_R_MAX[iCnt] / NUM ) * 2 )) ;

            }   

 

            //-- 16Bit

            if ( iBitsPerSample == 16 )

            {

                R_Point[iCnt].y = (int) ( (( cyClient / 2 ) + ( cyClient / 4 )) * (1 - sin (TWOPI * ia_R_MAX[iCnt] / NUM))) ;

            }           

        }

        Polyline ( MemDC, R_Point, NUM );     

    }   

    

    DRAW_HORIZONTAL_LINE ( hwnd, hdc) ;

    

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

    return TRUE ;

}

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                           끝--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                         시작--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL WRITE_FILE_INFOMATION (WAVEFORMATEXTENSIBLE waveFormatEx) ||

//_________________________________________________________________||

//                                                                 ||

//  WM_PAINT 에서 호출 : 파일정보를 기록한다.                      ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

BOOL WRITE_FILE_INFOMATION ( WAVEFORMATEXTENSIBLE waveFormatEx )

{

    wsprintf ( ca_wFormatTag,       "wFormatTag      - %d",     waveFormatEx.Format.wFormatTag ) ;

    wsprintf ( ca_nChannels,        "nChannels       - %d" ,    waveFormatEx.Format.nChannels ) ;

    wsprintf ( ca_nSamplesPerSec,   "nSamplesPerSec  - %d Hz" , waveFormatEx.Format.nSamplesPerSec ) ;

    wsprintf ( ca_nAvgBytesPerSec,  "nAvgBytesPerSec - %d" ,    waveFormatEx.Format.nAvgBytesPerSec ) ;

    wsprintf ( ca_nBlockAlign,      "nBlockAlign     - %d" ,    waveFormatEx.Format.nBlockAlign ) ;

    wsprintf ( ca_wBitsPerSample,   "wBitsPerSample  - %d" ,    waveFormatEx.Format.wBitsPerSample ) ;

    wsprintf ( ca_cbSize,           "cbSize          - %d" ,    waveFormatEx.Format.cbSize ) ;

    wsprintf ( ca_lpstrFile,        "File            - %s" ,    OFN.lpstrFile ) ;

 

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL SHOW_FILE_INFOMATION ( HWND hwnd )                        ||

//_________________________________________________________________||

//                                                                 ||

//  WM_PAINT 에서 호출 : 파일정보를 보여준다.                      ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

BOOL SHOW_FILE_INFOMATION ( HWND hwnd )

{

    HDC hdc ;

    hdc = GetDC ( hwnd) ;

 

    TextOut ( hdc, 10,  20, ca_wFormatTag,      strlen(ca_wFormatTag) ) ;

    TextOut ( hdc, 10,  40, ca_nChannels ,      strlen(ca_nChannels) );

    TextOut ( hdc, 10,  60, ca_nSamplesPerSec , strlen(ca_nSamplesPerSec) );

    TextOut ( hdc, 10,  80, ca_nAvgBytesPerSec, strlen(ca_nAvgBytesPerSec) ) ;

    TextOut ( hdc, 10, 100, ca_nBlockAlign,     strlen(ca_nBlockAlign) ) ;

    TextOut ( hdc, 10, 120, ca_wBitsPerSample,  strlen(ca_wBitsPerSample) ) ;

    TextOut ( hdc, 10, 140, ca_cbSize,          strlen(ca_cbSize) ) ;

    TextOut ( hdc, 10, 160, ca_lpstrFile,       strlen(ca_lpstrFile) ) ;

 

    ReleaseDC ( hwnd, hdc ) ;

 

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL WM_PAINT_FUNCTION ( HWND hwnd )                           ||

//_________________________________________________________________||

//                                                                 ||

//  WM_PAINT : WM_PAINT 메세지 처리                                ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

BOOL WM_PAINT_FUNCTION ( HWND hwnd )

{   

    HDC hdc ;

    PAINTSTRUCT ps ;    

 

    //-- Byte 단위의 값을 보여준다.

    //hdc = GetDC ( hwnd ) ;

    //SHOW_WAVE_DATA ( hwnd ,hdc ) ;

    //SHOW_WAVE_DATA ( hwnd ) ;

    //ReleaseDC ( hwnd, hdc ) ;

 

    hdc = BeginPaint ( hwnd, &ps ) ;

        

    DRAW_SINE_WAVE ( hwnd,      

             hdc,

             waveFormatEx.Format.wBitsPerSample,

             waveFormatEx.Format.nChannels ) ;

 

    BitBlt ( hdc, 0, 0, cxClient, cyClient , MemDC, 0, 0, SRCCOPY); 

    SelectObject ( MemDC, OldBitMap ) ;

    DeleteDC ( MemDC ) ;    

        

    EndPaint ( hwnd, &ps ) ;    

        

    return TRUE ;

}

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                           끝--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                         시작--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int MM_WOM_OPEN_FUNCTION ( HWAVEOUT hWaveOut, int BufferNum ) ||

//_________________________________________________________________||

//                                                                 ||

//-- hWaveOut 과 BufferNum을 넘겨 받는다.                          ||

//   - hWaveOut  : hWaveOut 핸들                                   ||

//   - BufferNum : 버퍼의 갯수                                     ||

//                                                                 ||

//-- waveOutWrite : 버퍼 재생이 끝나면  MM_WOM_DONE: 메세지를      ||

//                  발생시킨다.                                    ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int MM_WOM_OPEN_FUNCTION ( HWAVEOUT hWaveOut, int BufferNum )

{

    read_size = ( ( waveFormatEx.Format.nSamplesPerSec *

                    waveFormatEx.Format.nChannels *

                  ( waveFormatEx.Format.wBitsPerSample / 8 ) / 10 )  );

 

    if( read_size )

    {

        //MessageBox(hwnd, "MM_WOM_OPEN_FUNCTION ", "Message!", MB_OK);

    

        for( int i=0; i < BufferNum; i++)

        {

            // Allocate memory for wave header

            pWaveHdr[i] = ( WAVEHDR * ) malloc ( sizeof (WAVEHDR) ) ;

 

            pBuffer[i]  = ( BYTE * ) malloc (read_size);

            pWaveHdr[i]->lpData          = ( char * ) pBuffer[i] ;

            pWaveHdr[i]->dwBufferLength  = read_size ;

            pWaveHdr[i]->dwFlags         = WHDR_DONE;

 

            mmioRead ( hMMIO, ( char * ) pBuffer[i], read_size );

 

            waveOutPrepareHeader ( hWaveOut, pWaveHdr[i], sizeof (WAVEHDR) ) ;

        }

 

        for( int j=0; j < BufferNum; j++)

            waveOutWrite (hWaveOut, pWaveHdr[j], sizeof (WAVEHDR)) ;            

    }   

    return TRUE ;           

}

 

    

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int MM_WOM_DONE_FUNCTION ( HWAVEOUT hWaveOut, int BufferNum ) ||

//_________________________________________________________________||

//                                                                 ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int MM_WOM_DONE_FUNCTION ( HWND hwnd, HWAVEOUT hWaveOut , int BufferNum )

{   

    mRet = mmioRead ( hMMIO, ( char* ) pBuffer[CNT], read_size );

 

    if ( ( mRet == -1 )  || ( mRet == 0 ) ) // 1 is Error || 0 is File End

    {

        waveOutClose ( hWaveOut ) ;

        return FALSE;

    }

        

    waveOutWrite ( hWaveOut, pWaveHdr[CNT], sizeof ( WAVEHDR ) ) ;

 

    GET_SINE_WAVE ( waveFormatEx.Format.wBitsPerSample,

                    waveFormatEx.Format.nChannels,

                    pBuffer[CNT],

                    read_size ) ;

        

 

    CNT++;

    CNT %= BufferNum ;

 

    bEnding = FALSE ;

    bPlaying = TRUE ;

    

    return TRUE ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//-- int MM_WOM_CLOSE_FUNCTION (HWAVEOUT hWaveOut, int BufferNum ) ||

//_________________________________________________________________||

//                                                                 ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int MM_WOM_CLOSE_FUNCTION ( HWAVEOUT hWaveOut, int BufferNum )

{

    for ( int i=0; i < BufferNum; i++ )

    {

        waveOutUnprepareHeader ( hWaveOut, pWaveHdr[i], sizeof ( WAVEHDR ) ) ;

        free ( pWaveHdr[i] ) ;

        free ( pBuffer[i] ) ;

    }           

    mmioClose ( hMMIO, 0 ) ;

 

    bPaused = FALSE ;

    bPlaying = FALSE ;

    bEnding = TRUE ;                

        

    return TRUE ;

}

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//--연관된 함수 블록                                           끝--||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

// int FILE_OPEN ( HWND hwnd, OPENFILENAME OFN )                   ||

//_________________________________________________________________||

//                                                                 ||

//--IDC_FILEOPEN 처리 부분 - 파일 정보를 읽어온다.                 ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int FILE_OPEN ( HWND hwnd, OPENFILENAME OFN, HWAVEOUT hWaveOut )

{

    memset ( &OFN, 0, sizeof ( OPENFILENAME ) ) ;

    OFN.lStructSize = sizeof ( OPENFILENAME ) ;

    OFN.hwndOwner = hwnd ;

    OFN.lpstrFilter = "WAVE FILE (*.wav)\0*.wav\0" ;

    OFN.lpstrFile = caFileName ;

    OFN.nMaxFile = MAX_PATH ;

 

    if ( GetOpenFileName(&OFN) != 0 )

    {       

        GET_READ_CHUNK (OFN) ;                   // 파일 정보를 읽어온다.

        WRITE_FILE_INFOMATION ( waveFormatEx ) ; // 파일 정보를 기록한다.

        SHOW_FILE_INFOMATION ( hwnd ) ;          // 파일 정보를 보여준다.

 

 

        if (bPlaying)

        {                           

            waveOutReset (hWaveOut) ;   

            waveOutClose (hWaveOut) ;   

        }

        //GET_READ_CHUNK(OFN) ; 

 

 

        HDC hdc ;

        hdc = GetDC (hwnd) ;

        TextOut ( hdc, 300, 300, caFileName, strlen ( caFileName ) ) ;

        ReleaseDC ( hwnd, hdc ) ;

    }

 

    return TRUE ;

}

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

        

 

 

 

BOOL WM_CREATE_FUNCTION ( HWND hwnd )

{

    SetScrollRange ( hwnd, SB_HORZ, 0, xMax, TRUE ) ;

    SetScrollPos   ( hwnd, SB_HORZ, 0, TRUE ) ;

 

    //--Timer

    hTimer = ( HANDLE ) SetTimer ( hwnd, 1, 10, NULL );

 

    return 0 ;

}

 

 

BOOL WM_TIMER_FUNCTION ( HWND hwnd )

{

    GetLocalTime ( &st ) ;

    //RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE ) ;

    

    if ( bPlaying )

        InvalidateRect ( hwnd, NULL, FALSE ) ;

 

    return 0 ;

}

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM)          ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LRESULT CALLBACK WndProc ( HWND hwnd, UINT iMessage, WPARAM wParam,

                           LPARAM lParam )

{    

    CHOOSECOLOR COL;

    static COLORREF crTemp[16];

 

    switch ( iMessage )

    {       

    case WM_CREATE:

        WM_CREATE_FUNCTION ( hwnd ) ;

        return 0 ;

        

    case WM_TIMER:

 

        WM_TIMER_FUNCTION ( hwnd ) ;

        return 0 ;

 

    case WM_RBUTTONDOWN:

        memset(&COL, 0, sizeof(CHOOSECOLOR));

        COL.lStructSize = sizeof(CHOOSECOLOR);

        COL.hwndOwner=hwnd;

        

        //-- Full Size 로

        COL.Flags=CC_FULLOPEN;

        

        COL.lpCustColors=crTemp;

        if (ChooseColor(&COL)!=0) {

            Color=COL.rgbResult;

            InvalidateRect(hwnd, NULL, TRUE);

        }

        return 0;

 

    case WM_HSCROLL:

        switch (LOWORD(wParam))

        {

        }

 

    case WM_SIZE:

        WM_SIZE_FUNCTION ( lParam ) ;

        return 0 ;

 

    case WM_PAINT:

        WM_PAINT_FUNCTION ( hwnd ) ;

        return 0 ;        

 

    case WM_COMMAND:    

        switch ( LOWORD ( wParam ) )

        {                   

        case IDC_FILEOPEN:

            //FILE_OPEN ( hwnd, OFN, hWaveOut) ;            

            memset ( &OFN, 0, sizeof ( OPENFILENAME ) ) ;

            OFN.lStructSize = sizeof ( OPENFILENAME ) ;

            OFN.hwndOwner = hwnd ;

            OFN.lpstrFilter = "WAVE FILE (*.wav)\0*.wav\0" ;

            OFN.lpstrFile = caFileName ;

            OFN.nMaxFile = MAX_PATH ;

 

            if ( GetOpenFileName(&OFN) != 0 )

            {       

                GET_READ_CHUNK (OFN) ;                  

                

                if (bPlaying)

                {           

                    waveOutReset (hWaveOut) ;   

                    waveOutClose (hWaveOut) ;   

                }

                //GET_READ_CHUNK(OFN) ; 

            }

            return 0 ;

        

 

        case IDC_FILEEXIT:

            PostQuitMessage ( 0 ) ;

            return 0 ;

 

        case IDC_PLAY_BEG:  

            GET_READ_CHUNK ( OFN ) ;

            WAVE_BIT_CHECK () ; //-- 20 , 24 Bit 판별

 

            if ( waveOutOpen ( &hWaveOut, WAVE_MAPPER, (LPCWAVEFORMATEX) &waveFormatEx,

                               (DWORD) hwnd, 0, CALLBACK_WINDOW) )

            {

                MessageBeep (MB_ICONEXCLAMATION) ;

                MessageBox (hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK) ;

            }           

            bPlaying = TRUE ;               

            return 0 ;

 

        case IDC_PLAY_PAUSE:

            PLAY_PAUSE ( hWaveOut ) ;

            return 0 ;             

              

        case IDC_PLAY_END:

            PLAY_END ( hWaveOut ) ;

            return 0 ;               

 

        case IDC_SET_MUTE:

            IDC_SET_MUTE_FUNCTION ( hWaveOut ) ;

            return 0 ;

    }

    break; //-- InSide : case WM_COMMAND:

 

    case MM_WOM_OPEN:                           

        MM_WOM_OPEN_FUNCTION ( hWaveOut, BufferNum ) ;  

        return 0 ;          

 

    case MM_WOM_DONE:

        MM_WOM_DONE_FUNCTION ( hwnd, hWaveOut , BufferNum ) ;

        return 0 ;          

 

    case MM_WOM_CLOSE:      

        MM_WOM_CLOSE_FUNCTION ( hWaveOut, BufferNum ) ;     

        return 0 ;

 

    case WM_DESTROY:

        //-- Timer

        KillTimer ( hwnd, 1 ) ;     

        PostQuitMessage(0);     

        return 0 ;  

    }

 

    return(DefWindowProc(hwnd,iMessage,wParam,lParam));

 

}

 

 

 

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

 

 

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  WinMain()                                                      ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int APIENTRY WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,

                       LPSTR lpszCmdParam, int nCmdShow )

 

{

    HWND hwnd;

    MSG Message;

    WNDCLASS WndClass;

    g_hInst=hInstance;

    

    WndClass.cbClsExtra=0;

    WndClass.cbWndExtra=0;

    WndClass.hbrBackground=(HBRUSH)GetStockObject (BLACK_BRUSH); //(BLACK_BRUSH);  //(LTGRAY_BRUSH);  //(WHITE_BRUSH);

    WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

    WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

    WndClass.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));

    WndClass.hInstance=hInstance;

    WndClass.lpfnWndProc=(WNDPROC)WndProc;

    WndClass.lpszClassName=szAppName;

    //WndClass.lpszMenuName=NULL;

    WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MAIN_MENU);

    WndClass.style=CS_HREDRAW | CS_VREDRAW;

    RegisterClass(&WndClass);

 

    hwnd=CreateWindow

        (

          szAppName

        , szAppName  

        , WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES // WS_POPUPWINDOW

        , 0   

        , 0

        , 800 //-- 800 * 600 Mode 에 최적화

        , 600

        , NULL

        , (HMENU) NULL

        , hInstance

        , NULL

        ) ;

    

    // ShowWindow ( hwnd, nCmdShow ) ;

    ShowWindow ( hwnd, SW_SHOWMAXIMIZED ) ;  // 시작하자 마자 창 최대화 크기로..

    //UpdateWindow (hwnd) ;

    

    while ( GetMessage ( &Message, 0, 0, 0 ) )

    {

        TranslateMessage ( &Message ) ;

        DispatchMessage  ( &Message ) ;

    }

    return Message.wParam ;

}

이 글에 평점 주기:  

 

 

2002-08-22 오후 3:31:45   /  번호: 5028  / 평점:  (9.0) category: Sound  /  조회: 3,283 
 [API] 저수준 제어를 이용한 WAVE 재생 - WaveScope 트론의 유령 / lovesgh  
트론의 유령님께 메시지 보내기  트론의 유령님을 내 주소록에 추가합니다.  트론의 유령님의 블로그가 없습니다  

---------------------------------------------------------------------

 안녕하십니까? 유령입니다. 많이 늦어졌지요? 그간 이것저것 하느라 너무

바빠서..라는 핑계와 함께 강좌를 시작하겠습니다. 참고로 이 강좌에 쓰인

기법이나 구현기술은 저만의 방식대로 단지 흉내내는 것에 불과 하므로 실

제와 착오 없으시기 바랍니다. 실제 이런 프로그램(WaveLab 이나 CoolEdit

나 SoundForge 같은.. Wave를 편집할 수 있는 프로그램) 들이 어떻게 구현

하는지 저 나름대로 추측해서 만든 것이므로 실제로 쓰이는 기법이나 구현

에 관한 기술적인 내용에 있어서는 다를 수 있다는 말입니다.

 

->한 맺힌 절규 : 영어도 짧아서 관련정보를 구해 놓고도 제대로 써먹지도

                 못했다는..영어 공부 열심히 합시다..

---------------------------------------------------------------------

 

 일단 본 프로그램은 WaveLab 같은 프로그램을 써보신 분들은 아실테지만,

WaveLab 프로그램에서 WAVE 파일을 불러놓고 재생 시킬때,'Analysis' 메뉴

에 보면 Wave Scope라는 것이 있습니다. 이것을 흉내낸 것입니다. 일단 못

보신 분들을 위한 서비스 컷! 바로 아래가 지금 말하고 있는 것을 캡쳐 한

겁니다. 그리고 그 아래는 제가 만든 프로그램 입니다. 어떤가요? 거의 비

슷하죠? ^^..

 

[ WaveLab 프로그램의 Analysis -> Wave Scope ]


 

 

[ 유령이 만든 Wave Scope ]


 

---------------------------------------------------------------------

 

 자, 이번 강좌는 바로 저것을 만들어 보자! 입니다. 저는 저걸 보고 제일

먼저 생각한 것이..  바탕(배경)에 선이 그어져 있는 것이 보이시죠? 그걸

제일 먼저 그려보고 싶었습니다. 일단 검은 바탕으로 되 있길래 저는 검은

바탕으로 고정해 버렸습니다. 나중에야 알았지만, 색을 바꿀 수 있는 것이

었는데.. 윈도우 초기화 설정 부분에서 아래 부분이죠 ( API기준으로 ) ..

 

이 부분: WndClass.hbrBackground=(HBRUSH)GetStockObject (BLACK_BRUSH);

 

그 다음에는 이제 선을 그어야 겠죠. 일단 가운데(Center)에 선을 그어 봤

습니다. 가운데를 기준으로 그 위는 Left 채널이 되는것이고 아래는 Right

채널이 됩니다. ( 아쉽게도 이번 버젼은 2 채널 Stereo 방식까지만 지원합

니다. 다음에 5.1채널도 지원하는 걸 만들어 볼까요? ) 자 이제 왼쪽/오른

쪽 채널 구분선을 그었고, 다음으로는 왼쪽 채널의 Center 부분에 선을 그

었습니다. Right 채널도요. 각각 흰색 실선으로 그렸습니다. 그리고 그 센

터선을 기준으로 위/아래 선을 하나씩 또 그었죠. 센터선이 50%를 뜻 하기

때문에 각각 25% / 75% 지점이 되는 것이죠. 아래 그림을 참고하세요 ^^..

 


 

잠깐! - 여기서 짚고 넘어 갈 문제는.. 정말 중요한 겁니다. 저기 지금 위

        에 보이는 그림을 보세요. 25%, 50%, 75% 라고 되 있는데 이건 선

        의 위치상에 따른 '%'구분이지 실제 음의 높낮이와 관련된 기술적

        인 구분선은 아니라는 겁니다. 사실 각 채널 선의 50%부분은 무음

        상태이니까요..무음 - '0x80'

 

 자 이젠, 바탕에 채널을 분리하는 선과 멋지게(흉내만이라도)여러 선들을

그렸습니다. 참!! 그리기 전에 중요한 것은 나중에 Wave 선도 함께 화면에

함께 그려줄 것이기 때문에 화면깜빡임 현상이 발생할 수 있으니 메모리DC

를 이용해서 그리라는 것입니다. 메모리DC요? 저도 첨에 그거 잘못 썼다가

여러번 피봤습니다. 데브피아 질답란에서 하루종일 죽치고 앉아 검색해 보

니 많은 답변들이 있더군요. 다시 API에 맞게 고쳐서 했습니다. ^^.. 여러

분들도 만약 잘 모르시다면 데브피아 질/답란에 하루만 투자해 보세요. 누

구나 충분히 가능합니다.

 

---------------------------------------------------------------------

 

 자, 이제는 Wave 파일을 재생할 때 아래와 같이 그림으로 그려 줄 부분에

대해서 생각해 봅시다.

 


 저는 처음에는 뭣도 모르고 MoveToEx , LineTo 함수를 이용해서 그려댔다

가 괜히 제 평균고장시간(수명)만 단축시키는 꼴이 되고 말았습니다.더 좋

은 것이 있다는 걸 몰랐다니..바로 "Polyline" 이라는 함수더군요. 진작에

알았으면 좋았을 것을.. Wave 파일에서 각 해당하는 샘플의 바이트 단위로

정보를 읽어들여 그 내용을 Polyline이라는 함수에 넘기면 지가 알아서 멋

지게 그려주더군요. 일단 Wave 파일에서 값 을 읽어오는 부분에 대한 예제

를 먼저 보시죠. ( Wave파일은 8 Bit를 기준으로 합니다. 16/20/24/32 Bit

파일들도 원리는 같으니 구현해 보세요 ^^ )

 

--[ Wave 파일에서 값을 읽어오는 함수 부분 ]--------------------------

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL GET_SINE_WAVE ( int bit,                                  ||

//                       int isMonoStereo,                         ||

//                       void *buf,                                ||

//                       LONG bufsize )                            ||

//_________________________________________________________________||

//                                                                 ||

//--MM_WOM_DONE_FUNCTION에서 호출                                  ||

//                                                                 ||

//--넘겨 받은 버퍼의 내용 -> 수치화된 값 조사                      ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

#define NUM 1024

 

long ia_L_MAX[NUM] ;

long ia_R_MAX[NUM] ;

 

BOOL GET_SINE_WAVE ( int bit,int isMonoStereo,void *buf,LONG bufsize)

{

    BYTE  *pB ; // 1 Byte (BYTE)                

    int i;

    int cnt = bufsize / ( bit / 8 ) ; // 8:1, 16:2, 24:3, 32:4

    

    cnt /= isMonoStereo ;

 

    //-- 8 Bit

    if ( bit == 8 )

    {

        pB = ( BYTE * ) buf ;

 

        if ( isMonoStereo == 1 ) //-- Mono

        {

            for ( i = 0; i < NUM; i++ )

            {                                       

                ia_L_MAX[i] = (int) *pB ;

 

                pB ++ ;

            }

        }

 

        if ( isMonoStereo == 2 ) //-- Stereo

        {

            for ( i = 0; i < NUM; i++ )

            {                                       

                ia_L_MAX[i] = (int) *pB ;

                ia_R_MAX[i] = (int) *( pB + 1 ) ;

            

                pB += 2 ;           

            }

 

        }

    }

 

    return TRUE ;

}

 

---------------------------------------------------------------------

 

 함수머리를 한번 살펴볼까요? 지금까지의 제 강좌를 보신분들이라면 함수

머리만 봐도 대강 아시겠지만..

 

BOOL GET_SINE_WAVE ( int bit,int isMonoStereo,void *buf,LONG bufsize)

 

 함수 머리 부분을 잘 보면 다음의 인자들을 넘겨 받는다고 되어 있습니다

 

int bit          : waveFormatEx.Format.wBitsPerSample

int isMonoStereo : waveFormatEx.Format.nChannels

void *buf        : pBuffer[CNT]

LONG bufsize     : read_size

 

 각각의 인자들은 오른쪽 부분과 같은 것을 뜻하지요. 처음/두번째는 자주

쓰던 그 WAVEFORMATEXTENSIBLE 구조체 멤버들이지요.세번째는 현재 읽어들

인 버퍼구요. 마지막 네번째는 그 크기죠. 지난 강좌 보시면 됩니다. ^^..

 

long ia_L_MAX[NUM] ;

long ia_R_MAX[NUM] ;

 

 배열에 각각의 바이트만큼씩 저장합니다. 최대 크기는 1024입니다. 더 크

게 하거나 완전히 다 하거나 하려면 수정하시면 됩니다. ( 저는 실험을 위

해서 심플하게 1024로 잡은 것이고, 원래 제대로 만들려면 전부 집어 넣어

서 시간별로 체크가 가능해야 하겠죠. ) 이렇게 구한 값 들은 다음에 이어

질 함수에 사용됩니다.

 

---------------------------------------------------------------------

 

 자~ 이제 Wave 파일에서 값들도 추출해 냈으니 그것을 가지고 Wave파형을

멋지게 그려 줄 차례입니다. 아래에 해당 함수의 소스가 있습니다. 보세요

 

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//                                                                 ||

//  BOOL DRAW_SINE_WAVE ( HWND hwnd )                              ||

//_________________________________________________________________||

//                                                                 ||

//--WM_PAINT : WM_PAINT에서 호출                                   ||

//                                                                 ||

//--사인파형으로 그래프를 그린다.                                  ||

//                                                                 ||

//|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

#define TWOPI  (2 * 3.14159)

BOOL DRAW_SINE_WAVE ( HWND hwnd,

                      HDC hdc,

                      int iBitsPerSample,

                      int iChannels )

{       

    // 이미 비트맵이 만들어져 있으면 지운다.

    if (MemBit)

        DeleteObject(MemBit);

 

    MemBit = CreateCompatibleBitmap ( hdc, 1600, 1200) ;

    MemDC = CreateCompatibleDC ( hdc ) ;

    OldBitMap = ( HBITMAP ) SelectObject ( MemDC, MemBit ) ;

 

    //-- Wave 의 색깔 지정

    HPEN hpen, OldPen ;

    hpen = CreatePen ( PS_SOLID, 1, Color ) ;

    OldPen =( HPEN ) SelectObject ( MemDC, hpen ) ;

 

    POINT L_Point[NUM], R_Point[NUM] ;

 

    //- [L] Chnnel

    for ( int iCnt = 0 ; iCnt < NUM; iCnt++ )

    {

        L_Point[iCnt].x = iCnt * cxClient / NUM ;

        

        //-- 8 Bit

        if ( iBitsPerSample == 8  )

        {

            L_Point[iCnt].y = (int) ( ( cyClient / 6 ) + ( cyClient / 4 ) * (1 - sin (TWOPI * ia_L_MAX[iCnt] / NUM ) * 2 )) ;

        }   

    }

    Polyline ( MemDC, L_Point, NUM );   

 

 

    //-- Stereo 일때만 오른쪽 채널도 표시

    if ( iChannels == 2 )

    {

        //- [R] Chnnel

        for ( int iCnt = 0 ; iCnt < NUM; iCnt++ )

        {

            R_Point[iCnt].x =  iCnt * cxClient / NUM ;  

            

            //-- 8 Bit

            if ( iBitsPerSample == 8  )

            {

                R_Point[iCnt].y = (int) ( ( cyClient / 6 ) + ( cyClient / 2 ) + ( cyClient / 4 ) * (1 - sin (TWOPI * ia_R_MAX[iCnt] / NUM ) * 2 )) ;

            }   

        }

        Polyline ( MemDC, R_Point, NUM );     

    }       

    DRAW_HORIZONTAL_LINE ( hwnd, hdc) ;

 

    SelectObject ( MemDC, OldPen ) ;

    DeleteObject ( hpen ) ;

 

    return TRUE ;

}

 

---------------------------------------------------------------------

 

 이 부분에서 가장 고생??했던 부분은 x,y 좌표를 계산하는 것이었습니다.

그려질 부분이 센터에 기준이 맞춰지지 않고 전혀 엉뚱한 부분에 그려져서

는 곤란하겠죠.

 

L_Point[iCnt].y = (int) ( ( cyClient / 6 ) + ( cyClient / 4 ) *

                  (1 - sin (TWOPI * ia_L_MAX[iCnt] / NUM ) * 2 )) ;

 

 이런 무지막지한 계산방법은 동원하고 싶지 않았는데.. --+; 아마도 산수

를 잘하시는 분들이라면 ( cyClient / 6 ) + ( cyClient / 4 ) 를  하나의

수식으로도 합칠 수 있겠죠?? ^^.. 저는 했다가 괜히 이상하게 퍼져가지고

그냥 저런 방식으로 했습니다. 뽑아낸 값을 가지고 Wave 파형을 그리는 방

법에는 여러가지가 있을 수 있습니다.제가 제일 처음 했던 것은 그 위치들

에 대한 정보를 확인 하고자 점을 찍어서 보는 것이었는데, 영 아니더군요

..그래서 다음으로 쓴 것이 각 위치들 간격을 선으로 이어보자는 것이었습

니다. MoveToEx, LineTo 함수들을 이용해서 말이죠. 그런대로 꺾어지고 올

라가고 내려가는 모양새는 갖췄으나 여러가지 문제가 있었습니다.  거기서

한 동안 헤매다가(사실은 게임에 빠져서.. -ㅛ-)..Polyline 이라는 함수를

쓰게 됐습니다. 어떤 방법을 쓰느냐는 여러분의 자유 지만, 가능하면 제가

쓰던대로 Polyline 함수를 쓰는 것이 장수의 비결입니다.

 

 그 다음으로 고생?했던 부분은 화면에 뿌려진 Wave들이 마구마구 춤을 춘

다는 것이었습니다. (화면 깜빡임) 가능한한 깜빡임을 줄이려고 별별 짓을

다해봤으나.. 최대한 줄어들긴 했어도 깜빡임은 여전했습니다.누군가 화면

처리를 하는데 그렇게 많은 계산이 들어간 선을 뿌릴때는 메모리DC를 써보

라고 하더군요. 메모리DC를 써보니 그제서야 떨림이 멈추더군요.

 

 원래는 여러분의 몫으로 남겨둘려고 했는데, 그냥 설명하겠습니다. ^^...

 

//-- Memory DC 설정

HDC MemDC ; 

HBITMAP OldBitMap ;

HBITMAP MemBit ;

 

 일단 전역으로 다음과 같이 잡아주신 다음에, 그림을 그릴때는 무조건 메

모리DC에 그려줍니다. HDC MemDC ; 여기요.. MemDC 여기에 그려 주는 겁니

다. 이때 물론 화면에는 나오지 않죠 ^^.. 나중에 BitBlt로 복사를 해줘야

됩니다. 화면 중앙에 선을 긋는다고 하면 아래와 같이 하면 됩니다.

 

HPEN hpen, OldPen ;

 

//-- 한 가운데

hpen = CreatePen ( PS_DOT, 2, RGB ( 0, 0, 255 ) ) ;

OldPen = ( HPEN ) SelectObject ( MemDC, hpen ) ;

 

MoveToEx ( MemDC, 0, cyClient / 2, NULL ) ;

LineTo   ( MemDC, cxClient, cyClient / 2 ) ;

 

SelectObject ( MemDC, OldPen ) ;

DeleteObject ( hpen ) ;

 

 그리고 나서 WM_PAINT : 메세지 처리 부분에서 아래와 같이 BitBlt함수를

BitBlt ( hdc, 0, 0, cxClient, cyClient , MemDC, 0, 0, SRCCOPY ); 이런

식으로 써주시면 됩니다.

 

---------------------------------------------------------------------

 

 

 

 

--[ 끝으로 ]----------------------------------------------------------

 

 별것도 아닌것 가지고 강좌?랍시고 글을 쓰는 제가 한 없이 부끄럽긴 하지

만 가끔 날아오는 격려메일을 보면 힘이 솟곤 합니다. 이런 Wave 제어 쪽의

프로그래밍에 관심이 있는 분들이 많은데, 그 분들도 관련정보를 얻지 못해

아쉬워 하더군요. 저 역시 많이 고생?해서 만들었습니다. 좋은 정보를 기껏

구해놓으면 잘 되지 않거나 너무나 복잡해서 쓰기 힘들었거나..제가 제대로

이해를 못한 탓이겠죠. 여기 강좌?에 쓰인 기법이나 구현내용/용어 들은 제

가 멋대로 한 것들이기 때문에 전혀 다르거나 맞지 않을 수도 있습니다. 보

다 자세하고 전문적인 기술/구현에 관해서는 해당 분야의 전문가들이 써 놓

은 강좌 (솔직히 이런걸 찾기가 굉장히 힘이 들었습니다..아쉬운 부분이죠)

를 참고 하시거나 유용한 사이트를 방문해서 보시기 바라며, 제가 쓴것들은

이렇게도 구현을 흉내라도 낼 수 있겠구나.. 정도로 봐주시기 바랍니다. 전

체 소스도 함께 올릴테니 많은 분들이 더 좋은 방향으로 개선해서 이것보다

더 멋지고 제대로 된 프로그램으로 만들었으면 합니다. ^^.. 감사합니다...

 

                                                       - 트론의 유령 -

 

----------------------------------------------------------------------

 

 

--[ 본 강좌의 프로그램을 구할 수 있는 곳 ]----------------------------

 원래 같은 글에 업로드 시켰었는데, 잘 안되더군요?? 이상하게 32 Bit 프

로그램이 아니라는 에러메세지도 뜨고.. 그냥 링크를 걸어두겠습니다.....

 

http://phpschool.com/bbs2/inc_view.html?id=39507&code=talkbox2&start=

0&mode=search&s_que=트론의%20유령&field=name&operator=&period=last1ye

ar&category_id=

 

더럽게 길죠..

----------------------------------------------------------------------

 

 

--[ 최종 수정일 - 2002/08/22 ]----------------------------------------

 본 강좌는 잘못된 부분이나 부정확한 부분에 대한 해당부분의 수정/삭제가

사전통보없이 이뤄질 수 있습니다.

----------------------------------------------------------------------

 

이 글에 평점 주기:  
  2002-09-11 오전 11:39:29   /  번호: 5307  / 평점:  (-)  
 Re: 화면 떨림 이렇게 하면 어떨까요?? ^^;; 야리싸내 / yariman  
야리싸내님께 메시지 보내기  야리싸내님을 내 주소록에 추가합니다.  야리싸내님의 블로그가 없습니다  
그래프를 그리고 지우고를 반복하잖아여...

메모리 디시에 그렸다가 화면에 윈도우 전체를 다시 뿌리잖아여...

그렇다면

새로운 그래프를 그릴때  기존의 그래프 정보를 그대로 배경색으로

그려버리면 그래프가 지워지잖아여...

그리고 나서 점선만 다시 그리면 

떨림이 사라지지 않을까요?? ^^;;

문제는 어느게 더빠르냐는 거지요....

윈도우를 다시 뿌리는게 빠른지 아니면 그래프와 라인만 다시 그리는게 빠른지..^^;;
이 글에 평점 주기:  
  2002-09-11 오후 12:56:12   /  번호: 5309  / 평점:  (-)  
 Re: 화면 떨림은 해결 했습니다 ^^.. 트론의 유령 / lovesgh  
트론의 유령님께 메시지 보내기  트론의 유령님을 내 주소록에 추가합니다.  트론의 유령님의 블로그가 없습니다  
[1] 메모리 DC, 비트맵 -> Bitblt 로 해결 했습니다. 이젠 안 떨립니다..

^^.. 관심가져주셔서 감사합니다..

이 글에 평점 주기:  

'- 음악과 나 - > 『 짬 통 』' 카테고리의 다른 글

전체화면으로 전환  (0) 2006.05.18
fps 계산하기  (0) 2006.05.18
사각영역에 숨겨진 작은 비밀  (0) 2006.05.18
bit를 이해하자  (0) 2006.05.18
배열과 포인터는 전혀 다르다  (0) 2006.05.18