Suara polifonik dari mikrokontroler?

14

Saya dapat membuat suara monofonik dengan mengaktifkan satu pin ( pada tingkat yang bervariasi ) yang terhubung ke buzzer piezo.

Bagaimana saya bisa menghasilkan dua sinyal audio campuran dalam perangkat lunak untuk membuat polifoni?

Inilah kode yang saya gunakan untuk memainkan nada sederhana.

#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);
    }
}
Toby Jaffey
sumber
Hei bisakah benda ini mengeluarkan bahasa manusia? Maksud saya suka kata-kata?
Rick_2047
1
Lihatlah Cantarino - code.google.com/p/tinkerit/wiki/Cantarino
Toby Jaffey
@ Boby sumber daya yang Anda berikan sangat bagus tapi saya melihat demo, itu sebenarnya tidak mengatakan apa pun yang terdengar. Ada lagi yang Anda tahu?
Rick_2047
Bukan tanpa DAC, tidak.
Toby Jaffey
@Joby apa yang Anda miliki dengan DAC?
Rick_2047

Jawaban:

8

Nah satu trik mudah adalah dengan menggunakan dua pin dengan PWM, dan ikat mereka ke sisi yang berlawanan dari speaker. Kemudian memodulasi setiap pin dengan kecepatan yang berbeda, dan Anda dapat memainkan dua not sekaligus ... pada dasarnya speaker mencampurnya untuk Anda. Lebih dari dua catatan dan Anda harus melakukannya dalam perangkat lunak seperti yang disebutkan.

davr
sumber
1
Jika Anda menggunakan PWM (beralih pada frekuensi yang jauh lebih tinggi dari sinyal yang diinginkan), maka Anda sudah dapat mencampur beberapa sinyal menjadi satu dengan hanya menggunakan satu pin output.
endolith
5

Cara standar untuk mendapatkan polifoni adalah dengan menginterupsi pada tingkat interupsi tetap (paling sering 8000 Hz atau 44100 Hz), dapatkan "tinggi" (+1) atau "rendah" (-1) (atau sesuatu perantara) dari masing-masing sumber suara. , tambahkan semua angka untuk mendapatkan total, lalu kirim nomor total itu keluar DAC.

Seperti yang orang lain katakan di sini, dengan sedikit kepandaian, PWM kecepatan tinggi dapat menggantikan DAC.

Halaman "mikrokontroler polifoni" memberikan beberapa detail dan kiat.

davidcary
sumber
3

Saya pikir permata game PC DOS tua yang bagus ini menggunakan suara polifonik nyata melalui speaker PC: Digger .

Saya tidak tahu bagaimana mereka membuatnya, tetapi Anda dapat mengunduh kode sumber C dari situs.


sumber
Saya masih dapat mendengar nada di kepala saya
Toby Jaffey
2

Ini mungkin membantu -> DAC PWM sederhana

Jim
sumber
Untuk membuat Arduino memainkan not secara serempak Anda harus menggunakan sistem yang mirip dengan MIDI - dengan perintah terpisah untuk note on dan note dll, built-in library nada melakukan ini tetapi tidak melakukan polifoni - tetapi versi terbaru terlihat seperti ya - code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
Jim
2

Jika Anda menggunakan perangkat lunak untuk menghitung waktu acara speaker Anda, pendekatan termudah mungkin adalah menghasilkan dua aliran data independen dan bergantian di antara mereka. Pendekatan ini dapat bekerja dengan baik apakah output speaker dikontrol oleh pin I / O atau DAC. Sebagai contoh:

pemilih int;
fase uint16_t [8], freq [8];

void interrupt (batal) { pemilih ++; pemilih & = 7; fase [pemilih] + freq [pemilih]; DAC_OUT = sinewave [fase [pemilih] >> 8]; }

Di atas adalah pendekatan penting yang saya gunakan dalam kotak musik berbasis PIC pada tahun 1996 (menggunakan kode assembly daripada C). Perhatikan bahwa laju interupsi harus 8 kali laju sampel efektif, tetapi setiap interupsi hanya perlu melakukan pemrosesan untuk satu suara. Perhatikan bahwa jika pemfilteran keluaran baik, pendekatan ini akan menghasilkan 3 bit lebih banyak dari resolusi DAC efektif daripada akan menambahkan sampel secara numerik dan kemudian mengeluarkannya, tetapi akan menghasilkan banyak suara pada laju sampel dan kelipatannya. Dengan demikian penyaringan bahkan lebih penting daripada yang seharusnya.

supercat
sumber
1

Mereka biasa melakukan ini pada sistem game lama dan di zaman " speaker PC ", tapi saya tidak tahu caranya.

Tebakan pertama: Pikirkan gelombang yang akan Anda buat secara ideal, lalu bayangkan distorsi menjadi bentuk persegi yang sangat terpotong, lalu buat bentuk persegi itu dengan mengubah output Anda pada waktu yang tepat. Akan memiliki banyak intermodulation .

Pikiran kedua: Dapatkah Anda meningkatkan frekuensi osilasi dan output sinyal analog gaya PWM ?

endolit
sumber
2
Saya ingat melihat emulator NES sejak lama dan saya percaya mereka menggunakan tiga bentuk gelombang masing-masing dengan frekuensi yang dapat diprogram. Dua gelombang persegi dan satu gelombang segitiga.
mjh2007
... dan satu sumber suara, rupanya. en.wikipedia.org/wiki/NES_Sound_Format
endolith
1

Seperti telah disebutkan Anda bisa melakukan ini dengan cara yang sama seperti dulu dilakukan dengan speaker PC (yang hanya mendukung on / off opsional terpasang ke pengontrol PWM.) Pada dasarnya pemahaman saya tentang metode ini adalah bahwa Anda menghidupkan dan mematikan speaker. cukup cepat sehingga tidak pernah sepenuhnya hidup atau mati (sedikit seperti bagaimana catu daya mode kerja). Ini membuat speaker terus-menerus bergerak antara hidup dan mati, menghasilkan sinyal analog.

Satu-satunya gotcha adalah bahwa Anda membutuhkan pembicara nyata (saya pikir piezo bergerak begitu cepat hingga penuh dan terlalu cepat) dan Anda harus dapat beralih sedikit cukup cepat. Saya melakukan beberapa percobaan dan menghasilkan kecepatan maksimum sekitar 5MHz yang seharusnya cukup untuk sinyal audio 11.025 Hz (mungkin kualitas terbaik yang bisa Anda harapkan.)

Tentu saja 11025Hz @ 8-bit adalah 11 kilobyte / detik, yang jauh lebih cepat daripada kecepatan port serial. Itu hanya akan memungkinkan mungkin satu atau dua nilai audio untuk disimpan dalam flash, jadi Anda cukup banyak untuk memutar audio yang dihasilkan dengan cepat, asalkan menyisakan cukup waktu CPU untuk memutar speaker!

Ada beberapa metode lain untuk mencapai ini juga, dan sepertinya sudah ada implementasi untuk Arduino dari metode yang dijelaskan di atas.

Malvine
sumber
2
Anda dapat menggunakan filter sebelum speaker untuk memuluskan PWM, terlepas dari seberapa cepat speaker itu sendiri bergerak.
endolith
1

Putar suara A sejenak, seperti mungkin 50 ms lalu suara B dan beralih bolak-balik. Idenya adalah untuk beralih lebih cepat daripada yang bisa diketahui telinga dan itu akan terdengar seperti keduanya bermain pada saat yang sama.

Matt Williamson
sumber
1

Saya percaya ada perpustakaan nada untuk Arduino yang melakukan dua nada. Anda harus dapat mengadaptasi kode ke chip AVR yang Anda gunakan. Ada juga beberapa utas pembentuk gelombang yang sangat baik di arduino.cc

Jika Anda memutuskan untuk menambahkan DAC, saya memiliki contoh osilator yang dikontrol secara numerik di http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html Empat saluran output independen. Quad DAC dan referensi hanya sekitar $ 2 atau lebih.

jluciani
sumber
0

Ini kode saya untuk memainkan 2 lagu pada saat yang bersamaan. Maaf, Anda harus mendaftar ke AVR freaks untuk mendapatkan akses.

avra
sumber
4
Saya akan memberi Anda upvote jika Anda memposting kode di sini, atau ke suatu tempat saya tidak memerlukan akun ...
Toby Jaffey