Mikrodenetleyiciden gelen polifonik sesler?


14

Bir piezo ziline bağlı tek bir pimi ( değişen bir hızda ) değiştirerek monofonik sesler yapabilirim .

Polifoni oluşturmak için yazılımda nasıl iki karışık ses sinyali üretebilirim?

İşte basit bir melodi çalmak için kullandığım kod.

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

Hey bu şey insan dili yayabilir mi? Yani kelimeler gibi mi?
Rick_2047

1
Cantarino'ya bir göz atın - code.google.com/p/tinkerit/wiki/Cantarino
Toby Jaffey

@ Verdiğiniz kaynak harikaydı ama demoyu gördüm, aslında duyulabilir bir şey söylemiyor.
Rick_2047

DAC olmadan olmaz, hayır.
Toby Jaffey

@Joby Bir DAC ile neyiniz var?
Rick_2047

Yanıtlar:


8

Kolay bir hile, PWM ile iki pim kullanmak ve bunları hoparlörün karşı taraflarına bağlamaktır. Daha sonra her bir pimi farklı bir hızda modüle edin ve aynı anda iki nota çalabilirsiniz ... temel olarak hoparlör bunları sizin için karıştırıyor. İkiden fazla not ve yukarıda belirtildiği gibi yazılımda yapmanız gerekecek.


1
PWM kullanıyorsanız (istenen sinyalden çok daha yüksek bir frekansta geçiş), yalnızca tek bir çıkış pimini kullanarak birden fazla sinyali birlikte karıştırabilirsiniz.
endolith

5

Polifoni almanın standart yolu, bazı sabit kesme hızlarında (çoğunlukla 8000 Hz veya 44100 Hz) kesmek, her ses kaynağından "yüksek" (+1) veya "düşük" (-1) (veya ara bir şey) elde etmektir. , toplamı elde etmek için tüm sayıları toplayın, ardından bu toplam sayıyı DAC'a gönderin.

Diğerlerinin burada söylediği gibi, biraz zekayla yüksek hızlı bir PWM bir DAC'nin yerini alabilir.

"Mikrodenetleyici seslilik" sayfa biraz daha ayrıntı ve ipucu verir.


3

Bu güzel eski küçük PC DOS oyun gem PC hoparlör aracılığıyla gerçek polifonik ses kullandığını düşünüyorum: Digger .

Nasıl yaptıklarını bilmiyorum, ancak siteden C kaynak kodunu indirebilirsiniz.


Kafamdaki melodiyi hala duyabiliyorum
Toby Jaffey



2

Konuşmacı etkinliklerinizi zamanlamak için yazılım kullanıyorsanız, en kolay yaklaşım muhtemelen iki bağımsız veri akışı oluşturmak ve bunlar arasında geçiş yapmaktır. Bu yaklaşım, hoparlör çıkışı bir G / Ç pimi veya bir DAC tarafından kontrol ediliyor olsun, oldukça iyi çalışabilir. Örneğin:

int seçici;
uint16_t fazı [8], frekans [8];

geçersiz kesinti (geçersiz) { Seçici ++; Seçici ve = 7; faz [seçici] + frekans [seçici]; DAC_OUT = sinüs dalgası [faz [seçici] >> 8]; }

Yukarıda 1996'da PIC tabanlı bir müzik kutusunda kullandığım temel yaklaşım (C yerine montaj kodu kullanarak). Kesme oranının etkili örnekleme hızının 8 katı olması gerektiğini, ancak her kesme işleminin yalnızca tek bir ses için işlem yapması gerektiğini unutmayın. Çıktı filtrelemesi iyi ise, bu yaklaşım, numunelerin sayısal olarak eklenmesinden ve daha sonra çıktısından daha 3 bit daha etkili DAC çözünürlüğü vereceğini, ancak numune hızında ve katlarında çok fazla gürültü üreteceğini unutmayın. Bu nedenle filtreleme aksi halde olduğundan daha önemlidir.


1

Bunu eski oyun sistemlerinde ve " PC hoparlörleri " günlerinde yaparlardı, ama nasıl olduğunu bilmiyorum.

İlk tahmin: İdeal olarak yapacağınız dalgayı düşünün, sonra onu yoğun bir şekilde kırpılmış kare şekline dönüştürdüğünüzü hayal edin, ardından çıktınızı uygun zamanlarda değiştirerek bu kare şeklini oluşturun. Yine de intermodülasyon çok olurdu .

İkinci düşünce: Salınım ve çıkış analog sinyallerinin PWM tarzı frekansını büyük ölçüde artırabilir misiniz ?


2
NES emülatörüne uzun zaman önce baktığımı hatırlıyorum ve her birinin programlanabilir frekansta üç dalga formu kullandıklarına inanıyorum. İki kare dalga ve bir üçgen dalga.
mjh2007

... ve görünüşe göre bir gürültü kaynağı. en.wikipedia.org/wiki/NES_Sound_Format
endolit

1

Daha önce de belirtildiği gibi, bunu bir PC hoparlörü ile yapıldığı gibi yapabilirsiniz (yalnızca isteğe bağlı olarak bir PWM denetleyicisine bağlı açık / kapalı desteği vardır.) Temel olarak benim yöntemim, hoparlörü açıp kapamanızdır. hiçbir zaman tam olarak açık veya kapalı olmayacak kadar hızlı (bir anahtar modu güç kaynağının nasıl çalıştığı gibi.) Bu, hoparlörü sürekli olarak açık ve kapalı arasında hareket ettirerek analog bir sinyal üretir.

Sadece gotchas gerçek bir hoparlöre ihtiyacınız var (Bence bir piezo çok hızlı tam açık ulaşır ve çok hızlı kapanır) ve biraz yeterince hızlı geçiş yapabilmeniz gerekir. Bazı deneyler yaptım ve 11,025 Hz ses sinyali için yeterli olması gereken maksimum 5MHz'lik bir hız ile geldim (muhtemelen almayı umabileceğiniz en iyi kalite).

Tabii ki 11025Hz @ 8-bit, seri portun hızından çok daha hızlı olan 11 kilobayt / saniyedir. Flaşta sadece bir veya iki saniyelik ses depolanmasına izin verir, böylece hoparlörü çevirmek için yeterli CPU zamanı bırakması koşuluyla, anında oluşturulan sesi çalmakla hemen hemen sınırlısınız!

Bunu başarmak için birkaç yöntem daha var ve Arduino için yukarıda açıklanan yöntemin zaten bir uygulaması var gibi görünüyor .


2
Hoparlörün kendisinin ne kadar hızlı hareket ettiğinden bağımsız olarak PWM'yi düzgünleştirmek için hoparlörden önce bir filtre kullanabilirsiniz.
endolith


1

A sesini bir an için çalın, belki 50 ms gibi, sonra B sesi ve ileri geri geçiş yapın. Fikir, kulağın anlatabileceğinden daha hızlı geçiş yapmaktır ve her ikisi de aynı anda çalıyormuş gibi gelecektir.


1

Arduino için iki ton yapan bir ton kütüphanesi olduğuna inanıyorum. Kodu kullandığınız AVR yongasına uyarlayabilmeniz gerekir. Ayrıca arduino.cc'de birkaç mükemmel dalga formu oluşturma ipliği vardır.

DAC eklemeye karar verirseniz, http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html Dört bağımsız çıkış kanalında sayısal olarak kontrol edilen bir osilatör örneğim var . Dörtlü DAC ve referans sadece yaklaşık 2 $ 'dır.


0

İşte aynı anda 2 melodiyi çalmak için kodum. Üzgünüz, erişim için AVR ucubeye kayıt olmalısınız.


4
Kodu buraya gönderirseniz veya bir hesaba ihtiyacım olmadığında size bir oy verebilirim
Toby Jaffey
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.