원본출처 : https://markheath.net/post/how-to-convert-byte-to-short-or-float
C#에서 오디오 코드를 작성할 때 자주 발생하는 문제 중 하나는 짧은 값으로 표시하는 것이 더 좋은 원시 오디오를 포함하는 바이트 배열을 얻는 것이다(Int16) 배열 또는 플로트(float)Single) 배열. (일부 오디오는 32비트 인트, 64비트 플로팅 포인트, 그리고 24비트 오디오 등) 다른 형식도 있다. C/C++에서 솔루션은 간단하다. 바이트 배열의 주소를 에 캐스팅한다. short * 또는 a float * 각 샘플에 직접 액세스하십시오.
불행히도 .다른 유형으로의 NET 주조 바이트 배열은 허용되지 않음:
byte[] buffer = new byte[1000];
short[] samples = (short[])buffer; // compile error!
이것은 예를 들어 NAudio에서, NAudio에서, NAudio에서, NAudio에서, NAU WaveIn 반에서 a를 반환하다. byte[] 그 안에 DataAvailable 이벤트, 일반적으로 16비트 샘플로 수동으로 변환해야 한다(16비트 오디오를 녹음 중임). 이것을 하는 데는 여러 가지 방법이 있다. 다섯 가지 접근 방식을 살펴보고 성능 측정을 마치겠다.
BitConverter.ToInt16
아마도 개념적으로 가장 간단한 것은 시스템을 사용하는 것이다.비트콘버터 클래스. 이렇게 하면 바이트 배열의 임의 위치에 있는 한 쌍의 바이트를 Int16이 작업을 수행하려면 다음과 같이 하십시오. BitConverter.ToInt1616개의 버퍼에서 각 샘플을 읽는 방법은 다음과 같다.
byte[] buffer = ...;
for(int n = 0; n < buffer.Length; n+=2)
{
short sample = BitConverter.ToInt16(buffer, n);
}
IEEE 플로트 오디오를 포함하는 바이트 배열의 경우, 호출하는 것을 제외하고 원리는 유사하다. BitConverter.ToSingle24비트 오디오는 3바이트를 임시 4바이트 배열로 복사하여 사용할 수 있다. ToInt32.
비트콘버터에는 역변환을 하기 위한 GetBytes 방식도 포함되어 있지만, 그런 다음 수동으로 그 방법의 반환을 버퍼에 복사해야 한다.
비트 조작
비트 조작에 더 익숙한 사용자는 비트 시프트를 사용하고 또는 각 바이트 쌍을 샘플로 변환하는 것을 선호할 수 있다
byte[] buffer = ...;
for (int n = 0; n < buffer.Length; n+=2)
{
short sample = (short)(buffer[n] | buffer[n+1] << 8);
}
이 기술은 32비트 정수에 대해 확장될 수 있으며, 다른 어떤 기술도 잘 작동하지 않는 24비트에도 매우 유용하다. 그러나 IEEE 플로트의 경우 좀 더 까다롭기 때문에 다른 기법 중 하나를 선호해야 한다.
역변환을 위해서는 비트 조작 코드를 더 많이 써야 한다.
Buffer.BlockCopy
또 다른 옵션은 전체 버퍼를 올바른 유형의 배열로 복사하는 것이다. 완충제.BlockCopy는 다음과 같은 목적으로 사용될 수 있다.
byte[] buffer = ...;
short[] samples = new short[buffer.Length];
Buffer.BlockCopy(buffer,0,samples,0,buffer.Length);
이제 샘플 배열은 접근이 용이한 형태로 샘플을 포함하고 있다. 이 방법을 사용하는 경우 가비지 수집기에서 추가 작업을 수행하지 않도록 샘플 버퍼를 다시 사용하십시오.
역 변환의 경우 다른 작업을 수행할 수 있음 Buffer.BlockCopy.
WaveBuffer
NAudio가 소매를 걷어붙이고 있는 한 가지 멋진 트릭은 (Alexandre Mutel 덕택)이다. WaveBuffer class. 이것은 class를 사용한다. StructLayout=LayoutKind.Explicit 의 결합을 효과적으로 창조하는 것으로 귀속시키다. byte[], a short[], an int[] 그리고 a float[]. 이렇게 하면 C#을 "트릭"하여 바이트 배열을 마치 짧은 배열인 것처럼 액세스할 수 있다. 어떻게 작동하는지 자세히 읽어보십시오. NAUDIO는 안정성이 걱정된다면 수년 동안 아무 문제 없이 성공적으로 사용해 왔다.(유일한 gotcha는 아마도 아래처럼 반사를 사용하는 어떤 것에도 그것을 넘겨서는 안 된다는 것이다.)NET는 그것이 여전히 a라는 것을 알고 있다. byte[], 비록 그것이 a로 통과되었다 하더라도. float[]예를 들어, 에 사용하지 마십시오. Array.Copy 또는 Array.Clear). WaveBuffer 다음과 같이 자체 백업 메모리를 할당하거나 기존 바이트 배열에 바인딩할 수 있다.
byte[] buffer = ...;
var waveBuffer = new WaveBuffer(buffer);
// now you can access the samples using waveBuffer.ShortBuffer, e.g.:
var sample = waveBuffer.ShortBuffer[sampleIndex];
이 기법은 IEEE 플로트와도 잘 작동하며, 이를 통해 액세스된다. FloatBuffer 속성. 하지만 24비트 오디오에는 도움이 되지 않는다.
한 가지 큰 장점은 역변환이 필요 없다는 것이다. 그냥 에 써라. ShortBuffer그리고 수정된 샘플은 이미 byte[].
Unsafe Code (안전하지 않은 코드)
마지막으로 C#에는 마치 C++를 사용하는 것처럼 포인터를 사용하여 작업할 수 있는 방법이 있다. 이를 위해서는 프로젝트 어셈블리를 "안전하지 않은" 코드를 허용하도록 설정해야 한다. '불안심'은 조심하지 않으면 기억을 손상시킬 수 있다는 뜻이지만 경계를 벗어나지 않는 한 이 기법에는 전혀 안전하지 않은 것이 없다. 안전하지 않은 코드는 안전하지 않은 상황에 있어야 하므로 안전하지 않은 차단을 사용하거나 방법을 안전하지 않은 것으로 표시할 수 있다.
byte[] buffer = ...;
unsafe
{
fixed (byte* pBuffer = buffer)
{
short* pSample = (short*)buffer;
// now we can access samples via pSample e.g.:
var sample = pSample[sampleIndex];
}
}
이 기법은 IEEE 플로트에도 쉽게 사용할 수 있다. 인트 포인터를 사용한 다음 비트 조작을 통해 네 번째 바이트를 블랭킹하면 24비트도 함께 사용할 수 있다.
에 관하여 WaveBuffer, 역변환할 필요가 없다. 포인터를 사용하여 바이트 배열의 메모리에 샘플 값을 직접 쓸 수 있다.
퍼포먼스
그렇다면 이 방법들 중 어떤 것이 가장 잘 수행되는가? 의심은 있었지만, 언제나 그렇듯이 코드를 최적화하는 최선의 방법은 그것을 측정하는 것이다. 나는 4분짜리 MP3파일을 거쳐 WAV로 변환하여 한번에 수백밀리초 동안 최대 샘플 값을 찾는 간단한 테스트 애플리케이션을 설정했다. 이것은 파형 도면에 사용할 코드 유형이다. 나는 각각의 파일이 전체 파일을 통과하는 데 걸리는 시간을 측정했다(MP3를 읽고 해독하는 데 걸리는 시간은 제외했다). 나는 쓰레기 수거업자를 위해 일을 만들지 않는 코드를 쓰려고 조심했다.
각 기법은 타이밍에 있어서 상당히 일관성이 있었다.
디버그 빌드릴리스 빌드
비트콘버터 | 263,265,264 | 166,167,167 |
비트 조작 | 254,243,250 | 104,104,103 |
버퍼.BlockCopy | 205,206,204 | 104,103,103 |
웨이브버퍼 | 239.264.263 | 97,97,97 |
방문 | 173.172.162 | 98,98,98 |
보다시피 BitConverter 가장 느린 접근 방법이며, 아마도 피해야 할 것이다. Buffer.BlockCopy 나에게 가장 큰 놀라움이었다 - 추가 복사본은 너무 빨라서 매우 빨리 지불되었다. WaveBuffer 디버그 빌드는 놀라울 정도로 느렸지만 릴리스 빌드는 매우 훌륭했다. 특히 안전하지 않은 코드처럼 버퍼 핀을 꽂을 필요가 없다는 점에서 인상적이기 때문에 장기적으로 보면 가장 빠른 기술일 수 있다. 예상대로 안전하지 않은 코드는 매우 빠른 성능을 제공했다. 또 다른 방법은 오디오 처리를 하는 경우 릴리즈 빌드를 사용해야 한다는 것이다.
더 빠른 방법을 아는 사람? 댓글로 알려줘.
디지털 오디오의 기본 원리와 NAUDIO로 오디오 애플리케이션을 작성하는 방법에 대해 알아보시겠습니까?
내 PLuralsight 과정, 디지털 오디오 기본 원리 및 NAudio를 사용한 오디오 프로그래밍을 확인하십시오
출처 (원문) : https://markheath.net/post/how-to-convert-byte-to-short-or-float
'개발언어 > C#' 카테고리의 다른 글
[C#] 다른 Thread에서 UI접근하기 (0) | 2021.01.18 |
---|---|
[C#] 구조체 마샬링 참고 (0) | 2021.01.15 |
[C#] 배열 0으로 초기화(Enumerable.Repeat) (0) | 2021.01.13 |
[C#] OpenFileDialog에서 파일 이름만 얻어오기. (0) | 2020.12.22 |
[C#] 파일 다중선택 열기(OPENFILEDIALOG) (0) | 2020.12.22 |