Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Simple Audio Tone Generator

Looking for a (simple) Python tone generator to use in following script running on the RaspberryPi with USB sound card. On-fly tone on/off and frequency change are required.

import serial, time

ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.1)

def monitor(inp=0):
    if inp != inpold:
        if inp != 0:
            ser.setDTR(1)   # LED on (GPIO?)
                # start tone here, generate tone forever or change tone freq
        else:
            ser.setDTR(0)   # LED off
                # stop tone without clicks
        inpold = inp

while True:
    time.sleep(0.01)        # min length tone pulse 10 milliseconds
    input = ser.getCTS()    # or GPIO input
    monitor(input)
like image 681
Andy_hs Avatar asked May 16 '26 11:05

Andy_hs


2 Answers

So I've found several ways to do this and I am going to lay them in order of feasibility (easiest to apply first):-


Assumptions about the tone:-

  • Wave type = Sinusodial

  • Frequency = 440Hz


Way 1 (Offline track, no sound device/backend hassle)

1- Use the Audacity software (or any similar software) to create a particular tone and export it to a file.

2- From Audacity, pick "Generate" from the tabs above then choose "Tone" and put 440 next to the frequency.

3- From Audacity, pick "File" from the tabs above then choose "Export" and select export as any extension you like, preferably mp3. 'out.mp3'

4- pip install playsound

5- In python

import playsound
playsound.playsound('out.mp3')

Way 2 (flexible, but got to make sure backend works fine)

1- pip install pygame

2- If you're working under a Linux environment then please make sure you install the following libraries

libsdl1.2-dev libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev

3- In python

import numpy
import pygame

sampleRate = 44100
freq = 440

pygame.mixer.init(44100,-16,2,512)
# sampling frequency, size, channels, buffer

# Sampling frequency
# Analog audio is recorded by sampling it 44,100 times per second, 
# and then these samples are used to reconstruct the audio signal 
# when playing it back.

# size
# The size argument represents how many bits are used for each 
# audio sample. If the value is negative then signed sample 
# values will be used.

# channels
# 1 = mono, 2 = stereo

# buffer
# The buffer argument controls the number of internal samples 
# used in the sound mixer. It can be lowered to reduce latency, 
# but sound dropout may occur. It can be raised to larger values
# to ensure playback never skips, but it will impose latency on sound playback. 

arr = numpy.array([4096 * numpy.sin(2.0 * numpy.pi * freq * x / sampleRate) for x in range(0, sampleRate)]).astype(numpy.int16)
arr2 = numpy.c_[arr,arr]
sound = pygame.sndarray.make_sound(arr2)
sound.play(-1)
pygame.time.delay(1000)
sound.stop()

Way 3 (Sinusoidal Wave)

use this if all you need is a sinusoidal wave

1- pip install pysine

2- if you're working under a Linux environment then please make sure you install the following library

portaudio19-dev

however, if you're working under a Windows environment then please make sure you install this using pipwin

pipwin install pysine

3- In python

import pysine
pysine.sine(frequency=440.0, duration=1.0) 
like image 51
MedoAlmasry Avatar answered May 17 '26 23:05

MedoAlmasry


Try pysinewave. It allows you to start, stop, and smoothly change pitch and volume of a tone.
Example:

from pysinewave import SineWave
import time

sinewave = SineWave(pitch = 12)
sinewave.play()
time.sleep(1)
sinewave.stop()
like image 21
Ginger Avatar answered May 17 '26 23:05

Ginger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!