통합검색
· 마을서비스란?  · 포럼마을  · 일반마을  · 테마마을  · 마을랭킹  · 활동왕
· 덱스퍼트란?  · TECBOX   · PRSBOX   · 이용안내  
· DEXT제품군  · 솔루션베이  · S/W & ESD 컴포넌트
· 프로그램베이
· LiveSeminar  · LiveConference
Visual C++ 포럼마을 입니다.
  마을등급 Visual C++   이 마을은 포럼마을 입니다이 마을은 자유가입제 마을 입니다 마을소개 페이지로 이동 전입신청
마을촌장촌장 나성훈 주민 34013 since 2006-12-29
우리마을 공지사항
질문&답변
강좌&팁
자유게시판
자료실
앨범
개인게시판
마을 게시판
등록된 마을 게시판이
없습니다.
랑데브 게시판
칼럼 게시판
개발자 고충상담
Dev Talk
자유토론방
벼룩시장
재나미 우스개
구인/프로젝트 정보
사람인 채용 게시판
  고객지원 게시판
마이 데브피아
 나의 e-Money 내역
 활동왕 My Page
 스크랩한 게시글보기
 쪽지관리
 주소록관리

 강좌&팁
 [API] 저수준 제어를 이용한 WAVE 재생 - 04  | Sound 2002-06-12 오후 1:56:18
 lovesgh  lovesgh님께 메시지 보내기lovesgh님을 내 주소록에 추가합니다.lovesgh님의 개인게시판 가기 번호: 4379  / 읽음:5,122

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

 지금까지의 강좌로  WAVE 파일의 내부 구조라던지, 재생 원리, 버퍼의

구현등에 대해서 잘? 알게 되었을 거라고 .. 믿고 싶습니다. 이번 네번

째 강좌에서는 저번 강좌에 이어 실질적으로 윈도우 프로시저 내부에서

일어나는 메세지들을 처리하며 소리를 출력하는 과정을 살펴 보도록 하

겠습니다.

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

 

 WAVE 파일을 재생하기 위해서는 일단 파일의 위치에서 WAVE 파일을 읽

어 헤더정보를 알아내야 한다. 대략의 과정을 단순하게 표현 해 보자면

다음과 같다.

 

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

[처리]

 

파일을 여는 부분 :

 

    파일의 위치에서 파일을 읽는다.

 

    if ( 파일을 읽는데 성공했으면 )

    {       

        if ( 다른 곡이 재생 중이면 )

        {

            현재 재생 중인 곡의 버퍼를 비우고..

        }

    }

    

    return TRUE ;

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

 

 WAVE 파일을 읽는데 성공했으면 이제 PLAY 버튼을 눌렀을 때 일어나는

동작에 대해서 구현할 차례인데..

        

플레이 버튼을 눌렀음:               

    READ_CHUNK ( OFN ) ; // WAVE파일의 헤더를 읽음 ( 소스는 아래 )

 

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

         (DWORD) hwnd, 0, CALLBACK_WINDOW) )

    {

        MessageBeep ( MB_ICONEXCLAMATION ) ;

        MessageBox ( hwnd, szOpenError, szAppName,

                     MB_ICONEXCLAMATION | MB_OK) ;

    }                   

    return TRUE ;

 

 

여기서 waveOutOpen( ) 함수는 MM_WOM_OPEN 메세지를 발생 시킨다는 것

이 중요하다. ( 일단 위의 구현대로라면 그렇다. ) 이제 MM_WOM_OPEN메

세지를 처리해 줘야 하는데..여기서 더블 버퍼링 기법으로 버퍼를 설정

하고 WAVEHDR 을 설정해 준 다음에 read_size 만큼씩 WAVE 조각을 읽어

온다.

 

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

 

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

//                                                              ||

//-- 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.nSamplesPerSec * waveFormatEx.nChannels *

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

 

    if( read_size )

    {

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

        {

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

            pBuffer[i]  = (unsigned char *) 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( i=0; i < BufferNum; i++)

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

    }   

    return TRUE ;

}

 

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

 

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

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

 

 

이 부분이 실질적으로 소리를 출력하는 부분이다. 각 버퍼의 재생이 끝

나면 MM_WOM_DONE 이라는 메세지가 발생하는데,MM_WOM_DONE메세지의 처

리는 다음과 같이 해주면 된다. ( 원래는 MM_WOM_DONE : 메세지 처리부

분에서 해결해도 되나, 본인은 외부 함수로 빼내어 처리했다.. -> 윈도

프로시저 함수가 자꾸만 불어나서.. -_-a .. 터질까봐.. )

 

 

--[ MM_WOM_DONE_FUNCTION ]----------------------------------------

 

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

//                                                              ||

//-- 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 이면 에러 || 0 이면 파일 끝

    {

        waveOutClose ( hWaveOut ) ;

        return FALSE;

    }

    

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

 

    CNT++;             // 전체 버퍼 카운터 증가

    CNT %= BufferNum ; // 버퍼가 차례대로 돌아 가도록..

 

    return TRUE ;

}

 

버퍼 재생을 끝마쳤으면,  waveOutClose ( )를 이용해서 할당한 메모리

를 반납해주는 마무리 작업을 해줘야 하는데,  이 역시 외부 함수로 빼

내었다.

 

--[ MM_WOM_CLOSE_FUNCTION 의 소스 ]-------------------------------

 

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

//                                                              ||

//-- 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] ) ;

    }           

   

    mioClose ( hMMIO, 0 ) ;

    return TRUE ;

}

 

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

 

이런식으로 크게 3개의 메세지를 처리하면서  WAVE 파일이 재생이 반복

처리된다. 이번 강좌는 본인이 짠 함수 위주로 소스기재에 치우친 경향

이 있는데,사실 메세지를 처리하는 부분을 그냥 글로 설명하는 것 보다

는 실제로 어떤 함수들이 어떻게 연결되고 동작하는지를 보여주는 것이

훨씬 이해가 빠를 것이라 생각해서 소스 위주로 기재했다.  이제  모든

강좌는 끝이 났다. 여기 기재한 소스만으로도 재생을 위한 플레이어 정

도는 충분히 만들 수 있을 것이라 믿는다. 보너스?로 다음 회에는 소스

전량을 기재한다. -> 아직 완성된 것이 아니고.. 취미삼아 만들어 보는

수준이므로 여러가지 문제점 ( 본인이 발견한 문제점만도 여러가지.. )

이 있을 수 있으므로.. 이걸 해결하는 것은 여러분의 몫이다.( ^_^.. )

 

 

--[ READ_CHUNK 의 소스 ]------------------------------------------

 

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

//                                                              ||

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

//--------------------------------------------------------------||

//                                                              ||

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

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

//                                                              ||

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

int 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(WAVEFORMATEX)) == -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;

}

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

 

 

 

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

 

안녕하십니까!? 어설픈 WAVE 재생에 관한 강좌?를 끝내고.. 어떠셨는지

모르겠습니다. 본인도 아직 윈도우 프로그래밍의 달인은 커녕 걸인수준

도 안되는 관계로 여러가지 미흡한 부분도 있고, 글을 쓰면서도 마음속

에서는 계속해서.. ' 이게 아닌데.. -_- ' 하는 후회막급..  다음 강좌

에는 [ 시스템 볼륨 조절기 ] 나, 피크 메타 제작법, WAVE 파일을 읽어

들여 파형(웨이브 곡선) 그리기.. 등에 대한 강좌를 쓸까도 생각중이지

만, 일단은 반응을 살펴 본 뒤에.. ^_^ 쓰기로 하겠습니다.어떤 사람에

게는 쓰레기가 어떤 사람에게는 보물이 된다고 하죠.제 강좌가 어떤 분

들에게는 정말 쓰레기 같이 쓸모 없는 것일지라도.., 또 어떤 분에게는

( 단 한 사람이라도 )정말 중요한 자료가 되었으면 하는 바램으로 이번

강좌를 마치겠습니다. 감사합니다..!! ... 아싸.. 이제 좀 놀아야지...

 

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

 

                                                   - 트론의 유령 -

 

코멘트쓰기
  좋음   놀람   궁금   화남   슬픔   최고   침묵   시무룩   부끄럼   난감
* 코멘트는 500자 이내(띄어쓰기 포함)로 적어주세요.
목록 보기   지금 보고 계시는 글을 회원님의 my Mblog >> 스크랩에 넣어두고 다음에 바로 보실 수 있습니다.  
회사소개  |   개인정보취급방침  |  제휴문의  |   광고문의  |   E-Mail 무단수집거부  |   고객지원  |   이용안내  |   세금계산서
사업자등록번호 안내: 220-81-90008 / 통신판매업신고번호 제 2017-서울구로-0055호 / 대표: 홍영준, 서민호
08390, 서울시 구로구 디지털로32길 30, 1211호 / TEL. 02_6719_6200 / FAX. 02-6499-1910
Copyright ⓒ (주) 데브피아. All rights reserved.