[C#] 소리 파일(wav) 및 음악 파일(mp3)를 다루는 방법


Development note/C#  2021. 1. 27. 16:20

안녕하세요. 명월입니다.


이 글은 C#에서 소리 파일(wav) 및 음악 파일(mp3)를 다루는 방법에 대한 글입니다.


우리가 컴퓨터를 키면 업무적 이외로 가장 많이 사용하는 파일은 아마도 동영상이나 음악에 관계된 파일이지 않을까 싶습니다.

먼저 윈도우에서는 소리 파일을 기본적으로 wav 파일(Waveform audio format)을 사용합니다. 이 wav파일의 구조는 비트의 압축이 전혀없고 각 비트 단위마다 PCM(펄스 부호 변조) 데이터로 되어 있는 소리 파일을 뜻합니다.

using System;
using System.IO;
using System.Media;
using System.Threading;

namespace Example
{
  // FileStream을 상속받는다.
  class Program : FileStream
  {
    // 스피커로 소리를 내보낼 클래스
    private SoundPlayer sp;
    // 생성자
    public Program(string path) : base(path, FileMode.Open, FileAccess.Read)
    {
      // 인스턴스 생성
      sp = new SoundPlayer(this);
    }
    // 실행 함수
    public void Run()
    {
      // 사용법을 콘솔에 출력
      Console.WriteLine("P : Play , S: Stop, X is exit");
      while (true)
      {
        // 키를 입력받는다.
        var cmd = Console.ReadKey();
        // 콘솔 클리어
        Console.Clear();
        // 사용법을 콘솔에 출력
        Console.WriteLine("P : Play , S: Stop, X is exit");
        // 키 구분
        switch (cmd.Key)
        {
          // P키를 누를 경우
          case ConsoleKey.P:
            // 콘솔 출력
            Console.WriteLine("Playing...");
            // 비동기로 실행한다. (비동기로 하지 않으면 Play가 끝날때까지 인터럽트 걸린다.)
            ThreadPool.QueueUserWorkItem(_ => sp.Play());
            break;
          // s키를 누를 경우
          case ConsoleKey.S:
            // 콘솔 출력
            Console.WriteLine("Stop...");
            // 소리를 끈다.
            sp.Stop();
            break;
          // 루프를 종료한다.
          case ConsoleKey.X:
            // 콘솔 출력
            Console.WriteLine("Exit...");
            return;
        }
      }
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // 인스턴스 생성 (Wav 파일 실행)
      var p = new Program(@"d:\work\test.wav");
      // 실행 함수 호출
      p.Run();

      // 콘솔 출력
      Console.WriteLine("Press any key...");
      Console.ReadKey();
    }
  }
}

실행을 하면 사용법이 콘솔에 표시가 되고 P키를 누르면 소리가 나옵니다.(블로그에서는 소리가 나오는 결과를 확인할 수가 없네요....;;;)

다시 S키를 누르면 소리가 멈추고 다시 P를 누르면 소리가 처음부터 나옵니다. X를 누르면 프로그램을 종료하게 됩니다.


SoundPlayer 클래스는 C#에서 지원하는 기본적인 소리 출력 클래스입니다만, 소리를 구간별로 재생이 안되고 또 멈춤이나 현재 재생 중인 상태에 대해서도 정보가 없습니다.

사실 이 SoundPlayer는 음악 플레이어를 위한 것이 아니고 게임이나 기타 어플리케이션에서 효과음을 위한 클래스라고 생각하면 됩니다.

그러므로 우리가 많이 사용하는 mp3 음악 파일은 읽어서 소리 출력이 되지 않습니다.


사실 mp3파일을 사용하려면 stream으로 읽어와서 mp3를 wav파일로 변환(압축을 푸는)하는 라이브러리를 이용하거나 ffmpeg등을 이용하는 방법, 혹은 직접 mp3 구조체를 압축 해제하는 방법을 사용하는 방법밖에 없네요.

그래서 전혀 방법이 없는가 했더니 윈도우 환경에서는 Window media player가 기본적으로 설치가 되어 있더군요. 즉, 이 Window media player 객체를 끌어다 사용하면 mp3의 음악 파일을 실행할 수 있습니다.


먼저 COM(Component object model)에서 Window media player를 참조합니다.

using System;
using System.Threading;
using WMPLib;

namespace Example
{
  // 실행 클래스
  class Program
  {
    // 실행 함수
    static void Main(string[] args)
    {
      // 스레드 종료 여부
      bool IsAlive = true;
      // 정지 여부
      bool IsPause = false;
      // WindowsMediaPlayer 인터페이스인데??? 인스턴스가 생성이 되네요...
      WindowsMediaPlayer player = new WindowsMediaPlayer();
      // 스레드 시작
      ThreadPool.QueueUserWorkItem(_ =>
      {
        // mp3 파일
        player.URL = @"D:\work\test.mp3";
        // 무한 루프 시작
        while (true)
        {
          // 스레드 종료 여부
          if (IsAlive)
          {
            // 정지 여부
            if (!IsPause)
            {
              // 콘솔 클리어
              Console.Clear();
              // 사용법을 콘솔에 출력
              Console.WriteLine("P : Play , S: Stop, A: Pause");
              // 개행
              Console.WriteLine();
              // 현재 위치
              Console.WriteLine($"{player.controls.currentPositionString} / {player.currentMedia.durationString}");
              // 개행
              Console.WriteLine();
              // 볼륨
              Console.WriteLine($"Volume: {player.settings.volume}");
            }
            // 스레드 대기 0.1초
            Thread.Sleep(100);
            continue;
          }
          else
          {
            // 정지한다.
            player.controls.stop();
            break;
          }
        }
      });
      // 커맨더 무한 루프
      while (true)
      {
        // 사용자로 부터 입력 받는다.
        var cmd = Console.ReadKey();
        switch (cmd.Key)
        {
          // P키를 누르면
          case ConsoleKey.P:
            // 정지 플래그 해제
            IsPause = false;
            // 음악 플레이!
            player.controls.play();
            continue;
          // S키를 누르면
          case ConsoleKey.S:
            // 스레드 종료
            IsAlive = false;
            // 음악 종료
            player.controls.stop();
            break;
          // A키를 누르면
          case ConsoleKey.A:
            // 정지 플래그 설정
            IsPause = true;
            // 일시 정지
            player.controls.pause();
            // 명령어 삭제
            Console.WriteLine("\r  ");
            continue;
          // 기타키?
          default:
            continue;
        }
        break;
      }
      // 콘솔 출력
      Console.WriteLine("\rPress any key...");
      Console.ReadKey();
    }
  }
}

Console에서 음악 파일이 실행되어 소리나오는 것을 확인할 수 있습니다.

에제 프로그램을 만들다가 느낀건데 조금 손보면 나만의 음악 프로그램을 만들 수도 있을 것 같네요...


여기까지 C#에서 소리 파일(wav) 및 음악 파일(mp3)를 다루는 방법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.