1
\$\begingroup\$

I'm building a project that outputs audio via an Arduino to a powered computer speaker. This audio signal comes from a sine-wave-table lookup that I step through at various frequencies, setting a PWM pin to wave_table[0], then wave_table[1], etc...

I'd like to modulate the loudness of this signal, but I don't want to just divide the wave table value by an integer because I'm worried that it will distort the audio -- instead of having a range of 0-255 for the sine-wave it might only go 0-3 for example and then it's not a nice sine shape anymore.

Is there a way I can use a second Arduino PWM pin to control an amplifier to change the analog signal coming from the Arduino to modify the volume before it hits the speaker?

Thanks!!

\$\endgroup\$
4
  • \$\begingroup\$ Why not run the PWM faster and use the same sample multiple times? \$\endgroup\$ Aug 18, 2015 at 3:12
  • \$\begingroup\$ What audio frequencies are you trying to produce? \$\endgroup\$
    – Andy aka
    Aug 18, 2015 at 7:07
  • \$\begingroup\$ Yes, dividing the input table will distort the signal. An 8-bit PWM only gets you 48 dB SNR to begin with, and every divide-by-2 drops that by another 6 dB. This is why you haven't seen 8-bit DACs in computer sound cards since the early 1990s. \$\endgroup\$ Aug 18, 2015 at 10:12
  • \$\begingroup\$ By the way, you are aware that high-quality audio DAC chips are readily available, which will accept a digital wavetable over a common bus, right? I²S is common, but you could probably also find I²C or SPI versions. You might even find one with a built-in volume control. \$\endgroup\$ Aug 18, 2015 at 10:17

2 Answers 2

2
\$\begingroup\$

You can probably use a second PWM to generate a voltage and then send that into a VCA, or get an external digital potentiometer (DPOT) and use that to change the gain of an op-amp if you are willing to add additional ICs. However, if you don't need that many volume levels and you have a bunch of hardware PWMs already on your Arduino, you can just wire them together through some series resistors to create a summer circuit. Assuming your computer speaker has an amplifier built in with high input resistance, you should be able to add several (e.g. 4) PWM outputs together through 1K resistors.

As long as the PWMs were synchronized which they should be, you should get 1/4, 2/4, 3/4, and full amplitude using 4 channels (for example). Just make them all generate the same thing and turn some of the PWMs off (by setting it to be a digital 0) if you want to reduce the volume.

[EDIT] Actually, thinking about the problem some more, you can do it with even less hardware if you use the digital outputs as attenuation. Consider the following circuit:

schematic

simulate this circuit – Schematic created using CircuitLab

Each digital I/O basically gives you one bit of volume control, and you can get as many bits as you have extra I/Os. Your highest volume would be with all the digital I/Os set to "high-Z" or input, since your amplifier would just see the PWM. Setting any of the digital I/Os to output with a value of '0' would attenuate the signal, (e.g. if digital 0 was outputting a '0', your audio signal would be 50% attenuated due to voltage division). in the above case, you would have 8 volume levels, but you can easily extend the circuit if you need more bits. You can also make it a logarithmic taper by carefully picking resistor values.

\$\endgroup\$
4
  • \$\begingroup\$ interesting -- could I use a digital potentiometer and use it in a voltage divider? I need a voltage divider anyway to step down the 5V to 0.5V. \$\endgroup\$
    – user358829
    Aug 18, 2015 at 6:09
  • \$\begingroup\$ Yes, you can use a digital potentiometer as a voltage divider, or simply use it as a digitally controlled resistor to set your gain in an op-amp circuit. \$\endgroup\$
    – Zuofu
    Aug 18, 2015 at 6:10
  • \$\begingroup\$ @Zuofu: Changing the volume level in software probably isn't going to work. Human ears respond on a logarithmic scale, so you need lots of "bits" to play with. Presumably a full-scale signal comes out of the system somewhere around 90 dB SPL. If the OP needs to get down to library levels (30 dB) you need to divide the generated signal by 1,000 while still leaving enough dynamic range that the signal doesn't get pushed into the noise floor. No, a digpot or VCA is a far better plan. The summed PWMs could still be useful to get > 48 dB SNR, as you get from just one 8-bit PWM, though. \$\endgroup\$ Aug 18, 2015 at 10:07
  • \$\begingroup\$ You can play with the value of the resistors if you want the output to be weighted in some way. It will not be very hifi, but there is some value to designing circuits using hardware which has already been bought and paid for without adding to the BOM. Old synth chips like the ones found on early game consoles basically use the same tricks. \$\endgroup\$
    – Zuofu
    Aug 18, 2015 at 17:19
0
\$\begingroup\$

You could use a digitally controlled pot between the filter output and the audio input. Here's an example using the DS1669. (http://pdfserv.maximintegrated.com/en/ds/DS1669.pdf)http://pdfserv.maximintegrated.com/en/ds/DS1669.pdf

enter image description here

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.