¿Sonidos polifónicos de un microcontrolador?

14

Puedo hacer sonidos monofónicos alternando un solo pin ( a una velocidad variable ) conectado a un zumbador piezoeléctrico.

¿Cómo puedo generar dos señales de audio mixtas en el software para crear polifonía?

Aquí está el código que estoy usando para reproducir una melodía simple.

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

12 respuestas

8

Un truco sencillo es usar dos pines con PWM y atarlos a los lados opuestos del altavoz. Luego, modula cada pin a una velocidad diferente, y puedes tocar dos notas a la vez ... básicamente, el altavoz las mezcla para ti. Más de dos notas y tendrás que hacerlo en el software como se mencionó.

    
respondido por el davr
5

La forma estándar de obtener polifonía es interrumpir a una tasa de interrupción fija (a menudo 8000 Hz o 44100 Hz), obtener un "alto" (+1) o "bajo" (-1) (o algo intermedio) de cada fuente de sonido, sume todos los números para obtener un total, luego envíe ese número total a la DAC.

Como han dicho otros aquí, con un poco de inteligencia, un PWM de alta velocidad puede reemplazar un DAC.

La página "polifonía del microcontrolador" ofrece más detalles y sugerencias.

    
respondido por el davidcary
3

Creo que esta bonita y antigua joya del juego DOS para PC utilizó un sonido polifónico real a través del altavoz de la PC: Digger .

No sé cómo lo hicieron, pero puedes descargar el código fuente de C del sitio.

    
respondido por el herzmeister der welten
2

Esto podría ayudar - > DAC PWM simple

    
respondido por el Jim
2

simplemente puede agregar dos ondas cuadradas y usar pwm rápido para enviar la señal "analógica" al altavoz.

Aquí hay otro método diferente si te gusta el sonido del juego, rápido y sucio:

enlace

    
respondido por el neingeist
2

Si está utilizando un software para sincronizar los eventos de su altavoz, el enfoque más sencillo es probablemente generar dos flujos de datos independientes y alternar entre ellos. Este enfoque puede funcionar bastante bien ya sea que la salida del altavoz esté controlada por un pin de E / S o un DAC. Por ejemplo:

int selector;
uint16_t phase[8],freq[8];

void interrupt(void) { selector++; selector&=7; phase[selector] + freq[selector]; DAC_OUT = sinewave[phase[selector] >> 8]; }

Lo anterior es el enfoque esencial que utilicé en una caja de música basada en PIC en 1996 (usando el código de ensamblaje en lugar de C). Tenga en cuenta que la frecuencia de interrupción debe ser 8 veces la frecuencia de muestreo efectiva, pero cada interrupción solo tiene que hacer el procesamiento para una sola voz. Tenga en cuenta que si el filtrado de salida es bueno, este enfoque producirá 3 bits más de resolución DAC efectiva que la adición numérica de las muestras y luego la salida, pero generará una gran cantidad de ruido a la frecuencia de muestreo y múltiplos de la misma. Por lo tanto, el filtrado es aún más importante de lo que sería de otra manera.     
respondido por el supercat
1

Solían hacer esto en sistemas de juegos antiguos y en los días de " altavoces de PC ", pero no lo hago " No sé cómo.

Primero suponga: piense en la ola que idealmente haría, luego imagine distorsionarla en una forma cuadrada muy recortada, luego cree esa forma cuadrada alternando su salida en los momentos apropiados. Sin embargo, tendría un montón de intermodulación .

Segundo pensamiento: ¿Puede aumentar considerablemente la frecuencia de oscilación y emitir señales analógicas al estilo PWM ?

    
respondido por el endolith
1

Como se ha mencionado, podría hacer esto de la misma manera que solía hacerlo con un PC speaker (que solo admite el encendido / apagado opcionalmente conectado a un controlador PWM). Básicamente, mi comprensión del método es que enciende y apaga el altavoz lo suficientemente rápido como para que nunca esté completamente encendido o apagado (un poco como cómo una fuente de alimentación de modo conmutado funciona.) Esto hace que el altavoz se mueva constantemente entre encendido y apagado, generando una señal analógica.

El único problema es que necesitas un altavoz real (creo que un piezo se mueve tan rápido que llega a su máximo y se apaga demasiado rápido) y necesitas poder cambiar el bit lo suficientemente rápido. Hice algunos experimentos y se me ocurrió un máximo velocidad de alrededor de 5MHz , que debería ser suficiente para una señal de audio de 11,025 Hz (probablemente la mejor calidad que pueda esperar obtener).

Por supuesto, 11025Hz @ 8 bits es de 11 kilobytes / segundo, lo que es mucho más rápido que la velocidad de un puerto serie. Solo permitiría que se almacenara un segundo o dos de audio en el flash, por lo que está bastante limitado a reproducir el audio generado al vuelo, ¡siempre que quede suficiente tiempo de CPU para hacer girar el altavoz!

También hay un par de otros métodos para lograr esto, y parece que ya una implementación para el Arduino del método descrito anteriormente.

    
respondido por el Malvineous
1

Puedes agregar las secuencias como se describe aquí:

enlace

    
respondido por el terrace
1

Reproduzca el sonido A por un momento, como unos 50 ms, luego suene B y cambie de lugar. La idea es cambiar más rápido de lo que el oído puede decir y sonará como si ambos estuvieran tocando al mismo tiempo.

    
respondido por el Matt Williamson
1

Creo que hay una biblioteca de tonos para el Arduino que hace dos tonos. Debería poder adaptar el código al chip AVR que está utilizando. También hay un par de excelentes hilos de generación de forma de onda. en arduino.cc

Si decides agregar un DAC tengo un control numérico Ejemplo de oscilador en enlace Cuatro canales de salida independientes. El quad DAC y la referencia es solo alrededor de $ 2 o menos.

    
respondido por el jluciani
0

Aquí es mi código para tocando 2 canciones al mismo tiempo. Lo sentimos, tienes que registrarte con los fanáticos de AVR para obtener acceso.

    
respondido por el avra

Lea otras preguntas en las etiquetas