2008-10-06 4 views
10

저는 소프트웨어 신시사이저를 작성 중이며 44.1kHz 샘플에서 실시간으로 대역 제한, 별칭없는 파형을 생성해야합니다. Sawtooth 파형은 두 톱니파를 혼합하여 펄스 파형을 생성 할 수 있기 때문에 지금은 할 것입니다. 하나는 거꾸로되어 위상이 바뀌 었습니다.대역 제한 파형 생성

지금까지 나는 다음과 같은 방법을 시도했다 :

  1. 시작할 때 다른 bandlimit 주파수에서 하나의 사이클 완벽 대역 제한 파형 샘플을 사전 계산 한 후 함께 혼합 두 가장 가까운 사람을 재생. 괜찮아요.하지만 매우 우아하지는 않습니다. 많은 샘플이 필요하거나 그들 사이의 "간격"이 들립니다. 인터폴레이션과 믹싱 또한 꽤 CPU 집약적입니다.

  2. 톱니파를 얻기 위해 DC 보상 된 sinc 펄스 열을 통합합니다. DC 보상을 정확히 맞지 않으면 파가 제로에서 멀어지는 것을 제외하고는 훌륭한 소리를냅니다 (실제로는 까다 롭습니다). DC 문제는 적분기에 약간의 누설을 추가하여 줄일 수 있지만 저주파수를 잃게됩니다.

제 질문은 다음과 같습니다. 일반적인 방법은 무엇입니까? 제안 된 솔루션은 CPU의 측면에서 효율적이어야합니다. 실시간으로 많은 음성을 한꺼번에 처리해야하기 때문입니다.

+0

1 년 전이 질문에 대한 답변을 얻었지만이 문제에 걸림돌이있는 사람은 친숙하고 유능한 [DSP 및 플러그인 개발] (http://www.kvraudio.com/ –

답변

4

대역 제한 파형 생성에 접근하는 데는 여러 가지 방법이 있습니다. 평소처럼 품질에 대한 거래 비용을 처리하게 될 것입니다.

난 당신이 여기이 사이트에서 살펴 제안 :

http://www.musicdsp.org/

체크 아웃 아카이브! 그것은 좋은 재료로 가득차 있습니다. 나는 방금 "bandlimited"라는 키워드를 검색했다. 최소한 1 주일 동안 바쁘게 머물러 있어야하는 자료.

Btw - 내가 원하는 것인지는 모르겠지만 몇 년 전에 앨리어스가 감소 된 (예 : 실제로는 대역폭 제한이 없음) 파형 생성을 수행했습니다. 방금 마지막 샘플 위치와 현재 샘플 위치 사이의 적분 값을 계산했습니다. 전통적인 신스 - 파형의 경우, 특이점에서 통합 간격을 나눈다면 (예 : 톱니가 리셋 될 때) 쉽게 할 수 있습니다. CPU 부하가 낮고 품질이 만족 스럽습니다.

나는 동일한 드리프트 문제를 가지고 있었지만, 적분에 매우 낮은 차단 주파수를 갖는 고역 통과를 적용하면 그 영향이 제거되었습니다. 실제 analog-synth는 어쨌든 subhertz 지역으로 내려 가지 않으므로 많은 부분을 놓치지 않습니다.

+0

"phase + = (sampleRate/(float TableSize)/frequency;"는 컴파일되지 않습니다. "(sampleRate/(float TableSize))/빈도;"? – user877329

+0

좋은 링크! 많은 멋진 작은 스 니펫 – SvaLopLop

2

이것은 내가 Nils의 아이디어에서 영감을 얻은 것입니다. 다른 사람에게 유용 할 경우에 대비하여 여기에 붙여 넣으십시오. 간단히 말해서 상자 크기는 마지막 샘플의 위상 변화를 분석적으로 커널 크기 (또는 컷오프)로 사용하여 톱니파를 필터링합니다. 그것은 아주 잘 작동하고, 가장 높은 음표에는 약간의 소리가 나는 앨리어싱이 있지만, 정상적으로 사용하면 소리가 훌륭합니다.

에일리어싱을 줄이려면 커널 크기를 약간 늘려서 2 * phaseChange로 설정하면됩니다. 예를 들어 가장 높은 주파수를 잃어 버리더라도 좋을 것입니다.

비슷한 주제에 대해 SP를 검색 할 때 발견 된 또 다른 좋은 DSP 리소스는 다음과 같습니다. The Synthesis ToolKit in C++ (STK). 유용한 DSP 툴을 많이 가지고있는 클래스 라이브러리입니다. 그것은 심지어 대역 제한 파형 발생기를 사용할 준비가되어 있습니다. 그들이 사용하는 방법은 내가 첫 번째 게시물에서 설명한 것처럼 sinc를 통합하는 것입니다.

float getSaw(float phaseChange) 
{ 
    static float phase = 0.0f; 
    phase = fmod(phase + phaseChange, 1.0f); 
    return getBoxFilteredSaw(phase, phaseChange); 
} 

float getPulse(float phaseChange, float pulseWidth) 
{ 
    static float phase = 0.0f; 
    phase = fmod(phase + phaseChange, 1.0f); 
    return getBoxFilteredSaw(phase, phaseChange) - getBoxFilteredSaw(fmod(phase + pulseWidth, 1.0f), phaseChange); 
} 

float getBoxFilteredSaw(float phase, float kernelSize) 
{ 
    float a, b; 

    // Check if kernel is longer that one cycle 
    if (kernelSize >= 1.0f) { 
     return 0.0f; 
    } 

    // Remap phase and kernelSize from [0.0, 1.0] to [-1.0, 1.0] 
    kernelSize *= 2.0f; 
    phase = phase * 2.0f - 1.0f; 

    if (phase + kernelSize > 1.0f) 
    { 
     // Kernel wraps around edge of [-1.0, 1.0] 
     a = phase; 
     b = phase + kernelSize - 2.0f; 
    } 
    else 
    { 
     // Kernel fits nicely in [-1.0, 1.0] 
     a = phase; 
     b = phase + kernelSize; 
    } 

    // Integrate and divide with kernelSize 
    return (b * b - a * a)/(2.0f * kernelSize); 
} 
6

대역 제한된 파형을 생성하는 빠른 방법 중 하나는 대역 제한 단계 (BLEP)를 사용하는 것입니다. 당신은 대역 제한 단계 자체 생성 :

enter image description here

과 같이 파형을 만들려면 다음 대역 제한 단계 각 전환을 교체, 웨이브 테이블에 그것을 저장 :

enter image description here

워크 스루 (Band-Limited Sound Synthesis)를 참조하십시오.

이 BLEP는 실시간 파형을 생성하기위한 비인증 (이후 확장)이므로 MinBLEP이라는 최소 위상 대역 제한 단계를 사용하는 것이 좋습니다.이 단계는 동일한 주파수 스펙트럼 그러나 단지 과거로 확장 :

MinBLEPs 더 생각을 가지고 는 윈도우의 싱크을하는 최소 위상 복원을 수행 한 후 그 결과를 통합하고 테이블에 저장합니다. 이제 오실레이터를 만들려면 파형의 불연속 인 각 에 MinBLEP를 삽입하기 만하면됩니다. 따라서 에 방형 파인 을 삽입하면 톱니파 웨이브에 대해 값이 반전되는 MinBLEP를 삽입하지만 정상적으로 램프가 생성됩니다.

1

간단한 고역 통과 필터를 사용하면 블릿의 DC 오프셋을 줄일 수 있습니다! - DC 차단 캡을 사용하는 실제 아날로그 회로와 매우 비슷합니다!