파일 입출력에 관한 내용이다.
내가 필요한 것에 가장 가까운 편이라고 할 수 있겠다.
뭐 내가 필요한 것은 여기에다가 편집 기능까지 필요하지만, 그건 또 뒤에 나오겠지.
이 3장에서 다룰 것은 간단하게 얘기하면 파일을 읽는 방법과 파일을 쓰는 방법이다.
NAudio File Reader
NAudio에는 몇 가지의 FileReader 클래스가 있다. 이들은 각각이 WaveStream 클래스를 상속한(구현한) 클래스들로, 앞의 2강에서 입력으로서 기능했던 MP3FileReader 등을 말한다.
이들은 WaveFormat을 포함하고 있는데, 이는 그 오디오 파일의 속성(SampleRate, bps, channal count 등) 을 알려준다. 또한 reposition 기능을 지원하고 있다.
그리고 전체 오디오의 길이도 알려준다.
위 다섯 가지가 구현되어 있는 메인 리더들이다.
그리고 저들을 통합하는 것이 있으니 AudioFileReader 이다.
AudioFileReader
위 목록 중에서 마지막 Wma 를 제외한 넷을 합친 것이다.
ISampleProvider 인터페이스를 구현하며, 2강에서 봤다시피 볼륨 속성을 지니고 있어 볼륨 조절이 가능하다. 바꿔 말하면 위 네가지는 볼륨 조절 기능이 없어 추가적인 signal chain이 필요하다.
리턴은 IEEE float 형태의 PCM으로 보인다. 즉, 32bit이므로 16bit이나 24bit 일 경우 audioFileReader가 리턴하는 것을 그대로 저장하면 용량이 커질 수 있다.
사용하는데에는 매우 편리하지만 저장시에는 약간 유의할 필요가 있을 것 같다. 나는 이쪽을 사용할 듯.
WaveFileReader
기본적인 wav 파일을 읽는 리더 클래스이다. wav 파일이 그렇듯이 PCM이나 compressed를 다 읽을 수 있다.
file이나 stream에서 입력을 받아들일 수 있지만 완성된 파일이 아니면 reposition은 안된다.(당연하다)
RF64라는 것을 지원하는데 이는 헤더 크기를 변경하여 4GB 이상의 대용량 wav파일을 쓸 수 있게 해주는 것이다. 기존은 32bit라서 4GB가 최고 크기이다.
CueWaveFileReader 라는 클래스를 사용하여 metadate(아티스트, 제작일 등)를 읽어낼 수 있다.
MP3FileReader
자동으로 PCM으로 변환하는 기능을 제공한다.
디폴트로는 ACM codec을 사용하지만, 다른 것을 사용하도록 변환할 수 있다. 수동으로 추천되는 코덱은 nlayer.codeplax.com 의 오픈소스라고 한다. 아니면 DMO를 쓸 수도 있다고 한다.
기본적으로 윈도우 환경에서는 ACM이 제공되는게 일반적이지만, 경우에 따라 설치되지 않는 경우도 있다고 한다.
다만 이 부분은 중요하면서도 고려하기 꽤 어려운 부분이라는 생각이 들기는 한다...
단순히 파일 내용을 전부 읽어서 PCM으로 변환하기만 하는게 아니라, frame 단위로 읽을 수도 있다. 즉 raw frame에 접근할 수 있는 기능을 제공한다. ReadNextFrame 멤버함수를 사용하자.
이 기능을 이용해서 mp3 파일을 일부만 잘라낼(trim) 수도 있다. 원하는 시간대로 이동, frame 단위로 읽어서 그만큼만 쓰면 되니까. 다만 정확하게 ms 단위로 잘라낼 수는 없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public void TrimMp3File() { using (var mp3FileReader = new Mp3FileReader("demo.mp3", (wf) => new DmoMp3FrameDecompressor(wf))) using (var writer = File.Create("extract.mp3")) { var startPosition = TimeSpan.FromSeconds(60); var endPosition = TimeSpan.FromSeconds(90); // skip over the first 60 seconds mp3FileReader.CurrentTime = startPosition; while (mp3FileReader.CurrentTime < endPosition) { var frame = mp3FileReader.ReadNextFrame(); if (frame == null) break; writer.Write(frame.RawData, 0, frame.RawData.Length); } } } Colored by Color Scripter |
cs |
읽어낼 시 table of contents 를 작성하는데, 이는 파일의 길이를 읽어들여서 이 오디오 파일의 전체 길이 등을 알아내기 위한 작업이다.
그러다 보니, MP3의 목적과는 약간 엇나가게도 네트워크 스트리밍에서는 이 클래스를 쓸 수 없다. 나와는 큰 상관없지만.
또 ID3tag (v1,v2)를 찾아낼 수 있는 기능을 지원하지만 그 내용은 해석기능을 제공하지 않는다. 그게 필요하다면 taglib-sharp 라는 외부 라이브러리를 이용해야 한다.
MediaFoundationReader
vista부터 제공되는 media foundation 기능을 활용하는 클래스.
media foundation이 제공하는 모든 걸 읽을 수 있다. AAC나 WMA는 물론이고, mp4까지 읽을 수 있다. mp4를 읽을 경우 오디오 파일만 뽑아내는 형식이 된다.
역시 PCM을 리턴한다.
단점으로는 metadata에 엑세스할수 없다는 점.
NAudio File Writer
위의 reader와 반대되는 클래스이다. 이전 장에서는 출력이 사운드카드였다면, 여기서는 그 출력을 파일로 하는 것이다.
대체로 유의해야 하는 점은 dispose (소멸자)를 호출해야 한다는 점인데, using 문 안에서 writer를 쓰면 그 부분은 비교적 쉽게 해결된다.
주로 사용되는 클래스는 아래 네 가지이다.
WaveFileWriter
AiffFileWriter
WmaFileWriter
MediaFoundationEncoder
WaveFileWriter
쓰는 방식은 꽤 여러가지가 존재한다.
가장 기본적인 방식은 위처럼 reader에서 받은 데이터를 (혹은 signal chain의 결과로 나온 데이터를. IWaveProvider이기만 하면 된다) createWaveFile 로 출력하는 거다. 다만 이 경우 용량이 크므로, createWaveFile16 함수도 있다.
다만 이 경우 무제한으로 생성되는 provider는 사용해선 안된다. 그 경우에는 다른 방법으로 생성해야 한다.
일반 io 함수인 Write 함수나, WriteSample 함수도 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public void CreateBlankWavFile() { var format = new WaveFormat(16000, 1); using (var writer = new WaveFileWriter("blank.wav", format)) { var oneSecondSilence = new byte[format.AverageBytesPerSecond]; for (int n = 0; n < 10; n++) { writer.Write(oneSecondSilence, 0, oneSecondSilence.Length); } } } Colored by Color Scripter |
cs |
위는 빈 소리를 (10초) 만드는 코드이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public void CreateToneWaveFileEvenBetter() { var sampleRate = 44100; var channels = 1; var seconds = 15; var signalGenerator = new SignalGenerator(sampleRate, channels); signalGenerator.Type = SignalGeneratorType.Sin; signalGenerator.Frequency = 1000; signalGenerator.Gain = 0.25; var offsetProvider = new OffsetSampleProvider(signalGenerator); offsetProvider.TakeSamples = sampleRate * channels * seconds; WaveFileWriter.CreateWaveFile16("tone15.wav", offsetProvider); } Colored by Color Scripter |
cs |
위는 특정 시그널을 만들어서 집어넣는 함수로, 위 코드는 개선버전이 있는(효과는 동일하지만 코드가 깔끔해진다) 안 좋은 코드이지만 writesample을 보여주려고 넣었다.
wav 파일 합치기
여러 개의 wav 파일을 합친다. 단 여러개의 wav 파일의 포맷(WaveFormat 클래스 내용 전체) 는 반드시 동일해야 한다.
sample rate가 다르다거나 하면 합칠수 없다는 뜻이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public static void Concatenate(string outputFile, IEnumerable<string> sourceFiles) { var buffer = new byte[44100 * 2]; WaveFileWriter waveFileWriter = null; try { foreach (var sourceFile in sourceFiles) { using (var reader = new WaveFileReader(sourceFile)) { if (waveFileWriter == null) { // first time in create new Writer waveFileWriter = new WaveFileWriter(outputFile, reader.WaveFormat); } else { if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat)) { throw new InvalidOperationException( "Can't concatenate WAV Files that don't share the same format"); } } int read; while ((read = reader.Read(buffer, 0, buffer.Length)) > 0) { waveFileWriter.Write(buffer, 0, read); } } } } finally { if (waveFileWriter != null) { waveFileWriter.Dispose(); } } } Colored by Color Scripter |
cs |
뒤에 mp3도 섞어서 합치고 하는 걸 만들겠지만 일단은 이렇다.
'개발언어 > NAudio' 카테고리의 다른 글
[NAudio] 6. Recording Audio (0) | 2021.07.08 |
---|---|
[NAudio] 5. Working With Codecs (0) | 2021.07.08 |
[NAuidio] 4. Changing Wave Formats (0) | 2021.07.08 |
[NAudio] 2. Audio Playback (0) | 2021.07.08 |
[NAudio] 1. Introducing NAudio (0) | 2021.07.08 |