[Cocoa] NSSound를 통한 초간단 사운드 재생

코코아에는 소리를 재생할 수 있는 NSSound 클래스가 있다. NSSound는 소리 재생을 위한 작업을 극도로 단순화하는 클래스로 인스턴스 메소드를 사용하는 것만으로 간단히 사운드를 재생할 수 있다. NSSound는 AIFF, WAV, NextSND 포맷을 재생할 수 있다. 음향 데이터는 디스크 상의 파일이나, 네트워크상의 URL, 페이스트 보드에 복사한 데이터가 될 수 있다. 또한 시스템에서 사용하는 사운드는 경로가 아닌 이름으로 재생이 가능하다. 이러한 시스템 사운드는 /Library/Sounds 디렉토리에 저장되어 있다.

NSSound는 음향 데이터를 여러 방법으로 로딩할 수 있다. 기본적으로 시스템 라이브러리에 등록되어 있는 소리, 파일의 경로, URL 등으로부터 사운드를 로딩할 수 있다. 로딩된 사운드에 대해 시작 / 일시정지 / 일시정지후 재생 / 정지 등의 기본적인 playback 기능이 제공된다.  또한 NSSound는 델리게이트 메소드를 사용하여 사운드의 재생이 끝나는 시점에 특정한 동작을 실행할 수 있다.

이름으로 로딩하기

NSSound *mySound = [NSSound soundNamed:@"Temple"];

파일로부터 로딩하기

 
NSSound *mySound = [ initWithContentsOfFile:mySoundFilePath]

사운드 파일을 열려면 open panel 을 사용하면 된다.

-(IBAction)openSoundFilePanel
{
    int result;
    NSOpenPanel *panel = ;
    NSArray *filesToOpen;
    NSString *theFilename;
    NSMutableArray *fileTypes = ;

    ;
    result = ;

    if(result == NSOKButton) {
        filesToOpen = ;
        theFilename = [filesToOpen objectAtIndex:0];

        [self _loadSoundFromPath:theFilename];
        // 이미 정의해둔 재생 메소드
    }
}

URL로부터 로딩하기 – 파일시스템의 URL만이 적용 가능하다.

 NSSound *mySound = [ initWithContentOfURL:mySoundURL byReference:NO];

파일의 재생

-play, -pause, -resume, -stop 의 메소드를 보낸다. 파일의 재생이 완료되면 -sound:didFinishPlaying: 이 호출된다.
반복재생의 경우에는 loop 프로퍼티를 YES로 주면 된다. 음량은 0.0~1.0 사이의 값으로 줄 수 있다.

재생 프로그레스

전체 시간과 현재 재생 지점도 알 수 있다. -currentTime, -duration을 사용하면 된다. 타이머를 사용하며 매 순간의 현재 재생 위치를 표시하는 것이 가능하다.

아이폰에서는  이처럼 단순화된 클래스는 아직 존재하지 않는듯하다. 코어 오디오를 사용해서 재생해야 한다. 코어오디오는 iOS/OSX에서 음향을 다루는 총체적인 기능을 제공하는 프레임워크로 믹싱, 이퀄라이저 등을 내장하고 있으며 음질의 영향을 주지 않으면서 배터리 수명을 향상 시키는 기술이 적용되어 있다.

  • guest

    안녕하세요? 좋은 정보 감사합니다.
    제가 cocoa 완전 초짜인데

    wav파일의 file path를 textField에 입력받아 재생, 정지 등의 기능을 만들려고 합니다.
    NSSound를 이용하고 싶은데 (IBAction)play, (IBAction)pause, (IBAction)stop 등에 어떻게 코드를 써야할지 모르겠습니다.
    알려주시면 정말 감사하겠습니다.

    파일은 resource 폴더에 있지 않고, 외장하드에 들어있는 파일들입니다.
    ex) 입력 – /Volume/SAMSUNG/Music/CD1/Track01.wav

    • 본문 내용 그대로 하면 됩니다. (아마 UI는 그대로 있고, 텍스트필드 주소에 파일 경로를 적어두었다고 가정할 때)

      1. 특정 시점에 NSSound가 파일을 열어야 합니다. (OK 버튼을 넣거나, 텍스트 필드에 포커스가 빠질 때 엽니다.) 이 시점에 NSSound 인스턴스 객체를 하나 만듭니다.

      2. 파일의 경로가 완전하여 파일이 정상적으로 열린다면 NSSound 객체는 재생할 준비를 마칩니다. 뷰 컨트롤러는 이 NSSound 객체의 인스턴스에 play 메시지를 보냅니다.

      결국 말씀하시는 부분의 코드는 mySound 가 nil 인지 판별해서 play, pause, stop 메시지를 보내도록만 하면 됩니다.

      -(IBAction)play {
        if(self.mySound) [self.mySound play];
      }

      주소를 정확하게 텍스트 필드에 넣어두었다면 initWithContentOfFile: 에 그대로 넣어주기만 하면 됩니다. 도움이 되셨는지 모르겠네요. 질문에 대한 답이 너무 간단한데.. 전체 코드를 어떻게 만들어야 할지 감이 오지 않는다면 MVC 쪽을 조금 더 공부해보실 것을 추천드립니다.

    •  설명만으로는 힘든 것 같아서 아주 간단한 얼개만 코딩하여 소개합니다. https://www.box.com/s/d6aa2cf202b529cde03a 입력된 텍스트가 올바른 경로인지 체크하는 로직은 들어있지 않습니다. NSFileManager로 충분히 검사할 수 있습니다. 참고만 하시면 되겠네요.