เสียงโพลีโฟนิคจากไมโครคอนโทรลเลอร์หรือไม่?


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


@Joby ทรัพยากรที่คุณมอบให้นั้นยอดเยี่ยม แต่ฉันเห็นการสาธิตมันไม่ได้พูดอะไรที่ได้ยินเลยมีอะไรอีกที่คุณรู้จัก
Rick_2047

ไม่ใช่ถ้าไม่มี DAC ไม่ใช่
Toby Jaffey

@Joby คุณมีอะไรกับ DAC
Rick_2047

คำตอบ:


8

เคล็ดลับง่ายๆอย่างหนึ่งก็คือการใช้สองพินกับ PWM และผูกเข้ากับด้านตรงข้ามของลำโพง จากนั้นปรับแต่ละพินด้วยความเร็วที่แตกต่างกันและคุณสามารถเล่นโน้ตสองโน้ตได้ในครั้งเดียว ... โดยทั่วไปลำโพงจะผสมเข้าด้วยกันเพื่อคุณ มากกว่าสองบันทึกย่อและคุณจะต้องทำในซอฟต์แวร์ดังกล่าว


1
หากคุณใช้ PWM (การสลับที่ความถี่ที่สูงกว่าสัญญาณที่ต้องการ) คุณสามารถผสมสัญญาณหลาย ๆ สัญญาณเข้าด้วยกันโดยใช้เพียงขาออกเดียว
endolith

5

วิธีมาตรฐานในการรับโพลิกอนคือการอินเตอร์รัปต์ที่อัตราอินเตอร์รัปต์บางค่าคงที่ (ส่วนใหญ่ 8000 Hz หรือ 44100 Hz) รับ "สูง" (+1) หรือ "ต่ำ" (-1) (หรือระดับกลาง) จากแหล่งกำเนิดเสียงแต่ละแหล่ง เพิ่มตัวเลขทั้งหมดเพื่อรับผลรวมแล้วส่งตัวเลขทั้งหมดนั้นออก DAC

ดังที่คนอื่น ๆ พูดที่นี่ด้วยความฉลาดเล็กน้อย PWM ความเร็วสูงสามารถแทนที่ DAC

หน้า"microcontroller polyphony"ให้รายละเอียดและเคล็ดลับเพิ่มเติม


3

ผมคิดว่านี่เล็ก ๆ น้อย ๆ เก่าพีซีเกม DOS อัญมณีที่ดีใช้เสียงโพลีโฟนิจริงผ่านลำโพง PC: Digger

ฉันไม่ทราบว่าพวกเขาทำมันได้อย่างไร แต่คุณสามารถดาวน์โหลดซอร์สโค้ด C ได้จากเว็บไซต์


ฉันยังสามารถได้ยินเสียงเพลงในหัวของฉัน
Toby Jaffey

2

สิ่งนี้อาจช่วย -> PWM DAC อย่างง่าย


ในการทำให้ Arduino เล่นโน้ตแบบอะซิงโครนัสคุณจะต้องใช้ระบบที่คล้ายกับ MIDI - ด้วยคำสั่งแยกต่างหากสำหรับบันทึกย่อและปิดโน้ต ฯลฯ ห้องสมุดเสียงในตัวทำหน้าที่นี้ แต่ไม่ทำ polyphony - แต่เวอร์ชันล่าสุดดูเหมือน มันทำ - code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
Jim

2

คุณสามารถเพิ่มคลื่นสี่เหลี่ยมสองลูกและใช้ pwm อย่างรวดเร็วเพื่อส่งสัญญาณ "อนาล็อก" ไปยังลำโพง

นี่เป็นอีกวิธีหนึ่งที่แตกต่างกันหากคุณชอบเสียงของเกมรวดเร็วและสกปรก:

https://gitweb.bl0rg.net/cgi-bin/gitweb.cgi?p=arduinisten.git;a=blob;f=projekte/soundz/arpeggio/arpeggio.pde;h=6ceb64a57916c094e87e5983c07b5dd1b4623083;hb=HEAD


2

หากคุณกำลังใช้ซอฟต์แวร์เพื่อกำหนดเวลากิจกรรมลำโพงวิธีที่ง่ายที่สุดน่าจะสร้างสตรีมข้อมูลสองตัวและสลับระหว่างสตรีมข้อมูล วิธีการนี้สามารถทำงานได้ค่อนข้างดีไม่ว่าเอาต์พุตของลำโพงจะถูกควบคุมโดย I / O pin หรือ DAC ตัวอย่างเช่น:

ตัวเลือก int;
uint16_t เฟส [8], ความถี่ [8];

โมฆะขัดจังหวะ (เป็นโมฆะ) { เลือก ++; เลือก & = 7; เฟส [selector] + freq [selector]; DAC_OUT = sinewave [phase [selector] >> 8]; }

ข้างต้นเป็นวิธีการสำคัญที่ฉันใช้ในกล่องเพลงที่ใช้ PIC ในปี 1996 (ใช้รหัสการประกอบมากกว่า C) โปรดทราบว่าอัตราการขัดจังหวะจะต้องมีอัตราการสุ่มตัวอย่างที่มีประสิทธิภาพ 8 เท่า แต่การขัดจังหวะแต่ละครั้งจะต้องทำการประมวลผลสำหรับเสียงเดียว โปรดทราบว่าหากการกรองผลลัพธ์ดีวิธีนี้จะให้ความละเอียด DAC ที่มีประสิทธิภาพมากกว่าบิตที่เพิ่มตัวอย่างอย่างตัวเลขและเอาท์พุท แต่จะสร้างเสียงรบกวนจำนวนมากที่อัตราตัวอย่างและทวีคูณดังกล่าว การกรองจึงมีความสำคัญมากกว่าที่เป็นอื่น


1

พวกเขาเคยทำเช่นนี้กับระบบเกมเก่าและในยุคของ " ลำโพง PC " แต่ฉันไม่รู้ว่าจะทำอย่างไร

ก่อนอื่นให้เดาว่าคิดถึงคลื่นที่คุณสร้างขึ้นมาแล้วลองนึกภาพว่ามันบิดเบี้ยวเป็นรูปสี่เหลี่ยมที่ถูกตัดออกอย่างหนักแล้วสร้างรูปทรงสี่เหลี่ยมนั้นโดยการสลับสัญญาณของคุณในเวลาที่เหมาะสม จะมีจำนวนมากintermodulationแม้ว่า

ความคิดที่สอง: คุณสามารถเพิ่มความถี่ของสัญญาณอะนาล็อกและเอาท์พุตอนาล็อกแบบ PWM ได้หรือไม่?


2
ฉันจำได้ว่าเคยดูตัวจำลอง NES มานานแล้วและฉันเชื่อว่าพวกเขาใช้รูปคลื่นสามรูปในแต่ละรูปด้วยความถี่ที่ตั้งโปรแกรม คลื่นสี่เหลี่ยมสองลูกและคลื่นสามเหลี่ยมหนึ่งเส้น
mjh2007

... และแหล่งกำเนิดเสียงหนึ่งที่เห็นได้ชัด en.wikipedia.org/wiki/NES_Sound_Format
endolith

1

ตามที่ได้กล่าวไปแล้วคุณสามารถทำได้เช่นเดียวกับที่เคยทำกับลำโพง PC (ซึ่งรองรับเฉพาะการเปิด / ปิดที่ต่อพ่วงกับตัวควบคุม PWM) โดยทั่วไปความเข้าใจของฉันเกี่ยวกับวิธีการคือคุณเปิดและปิดลำโพง เร็วพอที่จะไม่สามารถเปิดหรือปิดได้อย่างเต็มที่ (เหมือนแหล่งจ่ายไฟของโหมดสวิตช์) ซึ่งจะทำให้ลำโพงเคลื่อนที่ไปมาระหว่างเปิดและปิดตลอดเวลาทำให้เกิดสัญญาณอะนาล็อก

gotchas เพียงอย่างเดียวคือคุณต้องมีวิทยากรตัวจริง (ฉันคิดว่าการเคลื่อนที่แบบเพียโซเร็วมากจนเต็มและเร็วเกินไป) และคุณต้องสามารถสลับบิตเร็วพอ ฉันทำการทดลองบางอย่างและความเร็วสูงสุดประมาณ 5MHzซึ่งน่าจะเพียงพอสำหรับสัญญาณเสียง 11,025 Hz (อาจเป็นคุณภาพที่ดีที่สุดที่คุณคาดหวังว่าจะได้รับ)

แน่นอนว่า 11025Hz @ 8-bit คือ 11 กิโลไบต์ / วินาทีซึ่งเร็วกว่าความเร็วของพอร์ตอนุกรมมาก มันจะอนุญาตให้เก็บค่าเสียงเพียงสองหรือสองค่าในแฟลชดังนั้นคุณจึงค่อนข้าง จำกัด ในการเล่นเสียงที่สร้างขึ้นในทันทีหากเหลือเวลา CPU ที่เพียงพอในการบิดลำโพง!

มีวิธีอื่นอีกสองสามวิธีในการบรรลุเป้าหมายนี้และดูเหมือนว่าจะมีการนำไปใช้สำหรับ Arduinoของวิธีการที่อธิบายไว้ข้างต้น


2
คุณสามารถใช้ตัวกรองก่อนที่ลำโพงจะทำการ PWM ให้ราบรื่นโดยไม่คำนึงว่าตัวมันจะเคลื่อนที่เร็วแค่ไหน
endolith


1

เล่นเสียง A สักครู่เช่นอาจจะ 50 มิลลิวินาทีแล้วเลือกเสียง B แล้วสลับไปมา ความคิดคือการเปลี่ยนเร็วกว่าหูสามารถบอกได้และมันจะฟังเหมือนเล่นทั้งสองในเวลาเดียวกัน


1

ฉันเชื่อว่ามีไลบรารีเสียงสำหรับ Arduino ที่ทำสองเสียง คุณควรจะสามารถปรับรหัสให้เข้ากับชิป AVR ที่คุณใช้งานอยู่ นอกจากนี้ยังมีเธรดการสร้างรูปคลื่นที่ยอดเยี่ยมอีกสองชุดที่ arduino.cc

หากคุณตัดสินใจที่จะเพิ่ม DAC ฉันมีตัวอย่าง oscillator ที่ควบคุมเชิงตัวเลขที่http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html สี่ช่องสัญญาณออกอิสระ Quad DAC และการอ้างอิงมีค่าประมาณ $ 2 เท่านั้น


0

นี่คือรหัสของฉันสำหรับการเล่น 2 เพลงในเวลาเดียวกัน ขออภัยคุณต้องลงทะเบียนเพื่อ AVR freaks เพื่อเข้าถึง


4
ฉันจะให้ upvote ถ้าคุณโพสต์รหัสที่นี่หรือที่อื่นฉันไม่จำเป็นต้องมีบัญชี ...
Toby Jaffey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.