마이크로 컨트롤러의 대위 소리?


14

피에조 버저에 연결된 단일 핀 ( 다양한 속도로 ) 을 토글하여 모노 포닉 사운드를 만들 수 있습니다 .

폴리포니를 만들기 위해 소프트웨어에서 두 개의 혼합 오디오 신호를 어떻게 생성 할 수 있습니까?

간단한 곡을 연주하는 데 사용하는 코드는 다음과 같습니다.

#define F_CPU 8000000UL // 8MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>

// number of timer0 overflows/sec
#define INT_PER_SEC 31250

// Frequencies (in Hz) of notes
#define F_FSH_4 370
#define F_A_4 440
#define F_B_4 494
#define F_E_4 330
#define F_CSH_5 554
#define F_D_5 587
#define F_FSH_5 740
#define F_CSH_4 277
#define F_GSH_4 415

// number of timer0 overflows for notes
#define REST -1 // special case
#define FSH_4 INT_PER_SEC/F_FSH_4
#define A_4 INT_PER_SEC/F_A_4
#define B_4 INT_PER_SEC/F_B_4
#define E_4 INT_PER_SEC/F_E_4
#define CSH_5 INT_PER_SEC/F_CSH_5
#define D_5 INT_PER_SEC/F_D_5
#define FSH_5 INT_PER_SEC/F_FSH_5
#define CSH_4 INT_PER_SEC/F_CSH_4
#define GSH_4 INT_PER_SEC/F_GSH_4

#define SEMIQUAVER_TIME 60  // ms
#define BREATH_TIME 20      // ms

volatile uint32_t intrs = 0;
volatile int32_t curNote = REST;

// TIMER0 overflow
ISR(TIMER0_OVF_vect)
{
    if (curNote == REST)
        intrs = 0;
    else
    {
        intrs++;
        if (intrs >= curNote)
        {
            PORTD ^= _BV(PD4);
            intrs = 0;
        }
    }
}


void play(int32_t note, uint32_t len)
{
    int i;
    curNote = note;
    for (i = 0; i< len; i++)
        _delay_ms(SEMIQUAVER_TIME);
    curNote = REST;
    _delay_ms(BREATH_TIME);
}

int main(void)
{
    /* setup clock divider. Timer0 overflows on counting to 256.
     * 8Mhz / 1 (CS0=1) = 8000000 increments/sec. Overflows every 256, so 31250
     * overflow interrupts/sec */
    TCCR0B |= _BV(CS00);

    // enable overflow interrupts
    TIMSK0 |= _BV(TOIE0);

    // PD4 as output
    DDRD = _BV(PD4);

    TCNT0 = 0;
    intrs = 0;

    curNote = REST;

    // enable interrupts
    sei();

    while (1)
    {
        // Axel F
        play(FSH_4, 2);
        play(REST, 2);
        play(A_4, 3);
        play(FSH_4, 2);
        play(FSH_4, 1);
        play(B_4, 2);
        play(FSH_4, 2);
        play(E_4, 2);
        play(FSH_4, 2);
        play(REST, 2);
        play(CSH_5, 3);
        play(FSH_4, 2);
        play(FSH_4, 1);
        play(D_5, 2);
        play(CSH_5, 2);
        play(A_4, 2);
        play(FSH_4, 2);
        play(CSH_5, 2);
        play(FSH_5, 2);
        play(FSH_4, 1);
        play(E_4, 2);
        play(E_4, 1);
        play(CSH_4, 2);
        play(GSH_4, 2);
        play(FSH_4, 6);
        play(REST, 12);
    }
}

이건 인간의 언어를 방출 할 수 있습니까? 나는 말처럼 의미합니까?
Rick_2047

1
- Cantarino 한 번 봐 가지고 code.google.com/p/tinkerit/wiki/Cantarino
토비 Jaffey

@Joby 당신이 준 리소스는 훌륭했지만 데모를 보았습니다. 실제로 들리는 말은 아닙니다.
Rick_2047

DAC 없이는 아닙니다.
Toby Jaffey

@Joby DAC와 함께 무엇을하십니까?
Rick_2047

답변:


8

한 가지 쉬운 트릭은 PWM과 함께 두 개의 핀을 사용하여 스피커의 반대쪽에 묶는 것입니다. 그런 다음 각 핀을 다른 속도로 변조하고 한 번에 두 개의 음을 연주 할 수 있습니다. 두 가지 이상의 메모가 있으므로 언급 한대로 소프트웨어에서해야합니다.


1
PWM (원하는 신호보다 훨씬 높은 주파수에서 스위칭)을 사용하는 경우 하나의 출력 핀만 사용하여 여러 신호를 함께 믹싱 할 수 있습니다.
endolith

5

폴리포니를 얻는 표준 방법은 고정 된 인터럽트 속도 (대부분 8000Hz 또는 44100Hz)로 인터럽트하고 각 음원에서 "높음"(+1) 또는 "낮음"(-1) (또는 중간 음)을 얻는 것입니다. 총계를 얻기 위해 모든 숫자를 더한 다음 총계를 DAC로 보냅니다.

다른 사람들이 말했듯이 약간의 영리함으로 인해 고속 PWM이 DAC를 대체 할 수 있습니다.

"마이크로 폴리포니" 페이지는 좀 더 세부 사항 및 팁을 제공합니다.


3

이 오래된 오래된 PC DOS 게임 젬은 PC 스피커를 통해 실제 대위 음향을 사용했다고 생각합니다 : Digger .

어떻게 만들 었는지 모르겠지만 사이트에서 C 소스 코드를 다운로드 할 수 있습니다.


여전히 내 머릿속에서 음악을들을 수 있습니다
Toby Jaffey

2

이것은 도움이 될 수 있습니다-> 간단한 PWM DAC


Arduino가 메모를 비동기식으로 재생하려면 MIDI와 유사한 시스템을 사용해야합니다. 음표를 켜거나 끄는 등 별도의 명령을 사용하면 내장 톤 라이브러리가이를 수행하지만 폴리포니는 수행하지 않지만 최신 버전은 다음과 같습니다. 그것은 않습니다 -code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
Jim


2

소프트웨어를 사용하여 스피커 이벤트 시간을 설정하는 경우 가장 쉬운 방법은 두 개의 독립적 인 데이터 스트림을 생성하고 이들 사이를 번갈아가는 것입니다. 이 접근법은 스피커 출력이 I / O 핀 또는 DAC에 의해 제어되는지 여부에 관계없이 매우 효과적입니다. 예를 들면 다음과 같습니다.

정수 선택기;
uint16_t 상 [8], 주파수 [8];

무효 인터럽트 (void) { 선택기 ++; 선택기 & = 7; 상 [선택기] + 주파수 [선택기]; DAC_OUT = 사인파 [위상 [셀렉터] >> 8]; }

위의 내용은 1996 년 PIC 기반 뮤직 박스에 사용 된 필수 접근 방식입니다 (C가 아닌 어셈블리 코드 사용). 인터럽트 속도는 유효 샘플 속도의 8 배 여야하지만 각 인터럽트는 단일 음성에 대한 처리 만하면됩니다. 출력 필터링이 양호하면이 방법은 샘플을 숫자로 추가 한 다음 출력하는 것보다 3 비트 더 효과적인 DAC 해상도를 생성하지만 샘플 속도 및 그 배수로 많은 노이즈를 생성합니다. 따라서 필터링은 다른 것보다 훨씬 중요합니다.


1

예전 게임 시스템과 " PC 스피커 " 시대에는이 작업을 수행했지만 방법을 모르겠습니다.

첫 번째 추측 : 이상적으로 만들 웨이브를 생각한 다음 크게 자른 사각형 모양으로 왜곡 한 다음 적절한 시간에 출력을 전환하여 사각형 모양을 만듭니다. 그러나 많은 상호 변조 가있을 것입니다 .

두 번째 생각 : 발진 주파수를 높이고 아날로그 신호를 PWM 스타일로 출력 할 수 있습니까 ?


2
오래 전에 NES 에뮬레이터를 본 것을 기억하며 프로그래밍 가능한 주파수를 가진 3 개의 파형을 사용했다고 생각합니다. 2 개의 구형파와 1 개의 삼각파.
mjh2007

... 그리고 분명히 하나의 소음원. en.wikipedia.org/wiki/NES_Sound_Format
endolith

1

앞에서 언급했듯이 PC 스피커 (PWM 컨트롤러에 선택적으로 연결된 켜기 / 끄기 만 지원)에서 동일한 방식으로이 작업 수행 할 수 있습니다 . 기본적 으로이 방법 에 대한 이해는 스피커를 켜고 끄는 것입니다. 스위치 모드 전원 공급 장치의 작동 방식과 비슷한 방식으로 완전히 켜지거나 꺼지지 않을 정도로 빠릅니다. 이렇게하면 스피커가 계속 켜지고 꺼지면서 아날로그 신호가 생성됩니다.

유일한 단점은 실제 스피커가 필요하다는 것입니다 (피에조가 너무 빨리 움직이며 너무 빨리 가득 차고 빨리 꺼집니다). 비트를 충분히 빨리 전환 할 수 있어야합니다. 나는 몇 가지 실험을했고 11,025 Hz 오디오 신호 (아마도 당신이 얻을 수있는 최고의 품질)에 충분 해야하는 약 5MHz의 최대 속도를 생각해 냈습니다 .

물론 8 비트에서 11025Hz는 초당 11 킬로바이트로, 직렬 포트 속도보다 훨씬 빠릅니다. 그것은 단지 1-2 초 정도의 오디오가 플래시에 저장되도록 허용 할 것이므로, 즉시 생성되는 오디오를 재생하는 데 거의 제한이 없으므로 스피커를 돌리는 데 충분한 여분의 CPU 시간이 남습니다!

이것을 달성하기위한 몇 가지 다른 방법이 있으며, 위에서 설명한 방법 의 Arduino대한 구현이미있는 것처럼 보입니다 .


2
스피커 자체의 속도에 관계없이 스피커 앞의 필터를 사용하여 PWM을 부드럽게 할 수 있습니다.
endolith


1

50ms 정도의 소리 A를 잠시 재생 한 다음 B를 소리 내고 앞뒤로 전환하십시오. 아이디어는 귀가 말할 수있는 것보다 빠르게 전환하는 것이며 동시에 재생되는 것처럼 들립니다.


1

Arduino에는 두 가지 톤을 수행하는 톤 라이브러리가 있다고 생각합니다. 사용중인 AVR 칩에 코드를 적용 할 수 있어야합니다. arduino.cc에는 몇 가지 우수한 파형 생성 스레드가 있습니다

DAC를 추가하기로 결정했다면 http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html 4 개의 독립적 인 출력 채널에 수치 제어 발진기 예제가 있습니다. 쿼드 DAC 및 기준은 약 $ 2 정도입니다.


0

다음 은 2 곡을 동시에 연주하는 코드입니다. 죄송합니다. 액세스하려면 AVR 괴물에게 등록해야합니다.


4
당신이 여기에 코드를 게시하거나 어딘가에 계정이 필요하지 않은 경우에 당신에게
공감대를 줄 것입니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.