Âm thanh đa âm từ vi điều khiển?


14

Tôi có thể tạo ra âm thanh đơn âm bằng cách bật một pin duy nhất ( ở tốc độ khác nhau ) được kết nối với một tiếng chuông tròn.

Làm cách nào tôi có thể tạo hai tín hiệu âm thanh hỗn hợp trong phần mềm để tạo đa âm?

Đây là mã tôi đang sử dụng để chơi một giai điệu đơn giản.

#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);
    }
}

Này thứ này có thể phát ra ngôn ngữ của con người không? Ý tôi là thích từ ngữ?
Rick_2047


@Joby tài nguyên bạn đã cung cấp rất tuyệt nhưng tôi đã xem bản demo, nó không thực sự nói bất cứ điều gì có thể nghe được. Bạn có biết gì khác không?
Rick_2047

Không phải không có DAC, không.
Toby Jaffey

@Joby bạn có gì với một chiếc DAC?
Rick_2047

Câu trả lời:


8

Một mẹo đơn giản là sử dụng hai chân với PWM và buộc chúng vào các cạnh đối diện của loa. Sau đó điều chỉnh mỗi pin ở một tốc độ khác nhau và bạn có thể phát hai nốt cùng một lúc ... về cơ bản, loa sẽ trộn chúng lại với nhau. Hơn hai lưu ý và bạn sẽ phải làm điều đó trong phần mềm như đã đề cập.


1
Nếu bạn đang sử dụng PWM (chuyển đổi ở tần số cao hơn nhiều so với tín hiệu mong muốn), thì bạn đã có thể trộn nhiều tín hiệu lại với nhau chỉ bằng một chân đầu ra.
endolith

5

Cách tiêu chuẩn để có được đa âm là ngắt ở một số tốc độ ngắt cố định (thường là 8000 Hz hoặc 44100 Hz), lấy "cao" (+1) hoặc "thấp" (-1) (hoặc một thứ trung gian) từ mỗi nguồn âm thanh , cộng tất cả các số để có tổng số, sau đó gửi tổng số đó ra bộ DAC.

Như những người khác đã nói ở đây, với một chút thông minh, một bộ điều khiển tốc độ cao có thể thay thế một bộ xử lý tín hiệu.

Trang "đa âm vi điều khiển" cung cấp thêm một số chi tiết và mẹo.


3

Tôi nghĩ rằng viên ngọc trò chơi PC DOS cũ nhỏ xinh này đã sử dụng âm thanh đa âm thực sự thông qua loa PC: Digger .

Tôi không biết họ đã tạo ra nó như thế nào, nhưng bạn có thể tải xuống mã nguồn C từ trang web.


Tôi vẫn có thể nghe thấy giai điệu trong đầu
Toby Jaffey

2

Điều này có thể giúp -> PWM đơn giản


Để cho Arduino phát các ghi chú một cách không đồng bộ, bạn sẽ cần sử dụng một hệ thống tương tự MIDI - với các lệnh riêng để ghi chú và ghi chú, v.v., thư viện âm thanh tích hợp thực hiện điều này nhưng không thực hiện đa âm - nhưng phiên bản mới nhất trông giống như nó có - code.google.com/p/rogue-code/wiki/ToneL LibraryDocumentation
Jim


2

Nếu bạn đang sử dụng phần mềm để định thời gian cho các sự kiện loa của mình, cách tiếp cận đơn giản nhất có lẽ là tạo hai luồng dữ liệu độc lập và luân phiên giữa chúng. Cách tiếp cận này có thể hoạt động khá tốt cho dù đầu ra loa được điều khiển bởi chân I / O hoặc DAC. Ví dụ:

bộ chọn int;
pha uint16_t [8], freq [8];

khoảng trống ngắt (void) { bộ chọn ++; bộ chọn & = 7; pha [bộ chọn] + freq [bộ chọn]; DAC_OUT = sin [pha [bộ chọn] >> 8]; }

Trên đây là cách tiếp cận thiết yếu mà tôi đã sử dụng trong hộp nhạc dựa trên PIC vào năm 1996 (sử dụng mã lắp ráp thay vì C). Lưu ý rằng tốc độ ngắt phải gấp 8 lần tốc độ mẫu hiệu quả, nhưng mỗi ngắt chỉ phải thực hiện xử lý cho một giọng nói. Lưu ý rằng nếu bộ lọc đầu ra tốt, phương pháp này sẽ mang lại độ phân giải hiệu quả hơn 3 bit so với việc thêm các mẫu bằng số và sau đó xuất ra chúng, nhưng nó sẽ tạo ra nhiều nhiễu ở tốc độ mẫu và bội số của chúng. Do đó, việc lọc thậm chí còn quan trọng hơn so với việc khác.


1

Họ đã từng làm điều này trên các hệ thống trò chơi cũ và trong thời của " loa PC ", nhưng tôi không biết làm thế nào.

Đầu tiên đoán: Hãy nghĩ về sóng mà bạn sẽ tạo ra một cách lý tưởng, sau đó tưởng tượng việc biến nó thành một hình vuông bị cắt xén nhiều, sau đó tạo ra hình vuông đó bằng cách bật đầu ra của bạn vào những thời điểm thích hợp. Sẽ có rất nhiều điều hòa , mặc dù.

Suy nghĩ thứ hai: Bạn có thể tăng đáng kể tần số dao động và đầu ra tín hiệu tương tự kiểu PWM không?


2
Tôi nhớ đã nhìn vào một trình giả lập NES từ lâu và tôi tin rằng họ đã sử dụng ba dạng sóng với tần số có thể lập trình được. Hai sóng vuông và một sóng tam giác.
mjh2007

... Và một nguồn tiếng ồn, rõ ràng. vi.wikipedia.org/wiki/NES_Sound_Format
endolith

1

Như đã đề cập, bạn có thể làm điều này giống như cách nó đã được thực hiện với loa PC (chỉ hỗ trợ bật / tắt tùy chọn gắn với bộ điều khiển PWM.) Về cơ bản, tôi hiểu về phương pháp này là bạn bật và tắt loa đủ nhanh để nó không bao giờ bật hoặc tắt hoàn toàn (giống như cách cung cấp năng lượng ở chế độ chuyển đổi hoạt động.) Điều này khiến loa liên tục di chuyển giữa bật và tắt, tạo ra tín hiệu tương tự.

Vấn đề duy nhất là bạn cần một người nói thật (tôi nghĩ rằng một chiếc bánh tròn di chuyển rất nhanh, nó phát ra đầy đủ và tắt quá nhanh) và bạn cần có khả năng chuyển đổi bit đủ nhanh. Tôi đã thực hiện một số thử nghiệm và đưa ra tốc độ tối đa khoảng 5 MHz, đủ cho tín hiệu âm thanh 11.025 Hz (có lẽ là chất lượng tốt nhất mà bạn có thể hy vọng có được.)

Tất nhiên 11025Hz @ 8-bit là 11 kilobyte / giây, nhanh hơn nhiều so với tốc độ của một cổng nối tiếp. Nó chỉ cho phép lưu trữ âm thanh trong một hoặc hai giây trong đèn flash, do đó bạn bị hạn chế rất nhiều khi phát âm thanh được tạo ra khi đang di chuyển, cung cấp đủ thời gian CPU dự phòng để xoay loa!

Có một vài phương pháp khác để đạt được điều này, và có vẻ như đã có một triển khai cho Arduino của phương pháp được mô tả ở trên.


2
Bạn có thể sử dụng bộ lọc trước loa để làm mượt PWM, bất kể loa di chuyển nhanh như thế nào.
endolith


1

Phát âm thanh A trong giây lát, như có thể 50 ms sau đó âm thanh B và chuyển đổi qua lại. Ý tưởng là để chuyển đổi nhanh hơn tai có thể nói và nó sẽ nghe giống như cả hai chơi cùng một lúc.


1

Tôi tin rằng có một thư viện giai điệu cho Arduino có hai âm. Bạn sẽ có thể điều chỉnh mã cho chip AVR bạn đang sử dụng. Ngoài ra còn có một vài chủ đề tạo dạng sóng tuyệt vời tại arduino.cc

Nếu bạn quyết định thêm một bộ xử lý tín hiệu, tôi có một ví dụ về bộ dao động điều khiển số tại http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html Bốn kênh đầu ra độc lập. Bộ tứ và tham chiếu chỉ khoảng 2 đô la trở lên.


0

Đây là mã của tôi để chơi 2 giai điệu cùng một lúc. Xin lỗi, bạn phải đăng ký vào freaks AVR để có quyền truy cập.


4
Tôi sẽ cung cấp cho bạn một upvote nếu bạn đăng mã ở đây hoặc đến một nơi nào đó tôi không cần tài khoản ...
Toby Jaffey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.