Python playTone(freq, duration) command for Learning and Teaching - python

I'm really baffled by this. I asked a few years back how to generate a tone with Python using something like playTone(freq, duration) and was overwhelmed by the complexity of the responses, and the lack of any simple solution.
The winsound module is inadequate as it trips over itself after a few notes, and is too limited in other ways (maybe 2 notes at a time would be nice, or a choice of wave types).
As a teacher, it makes a huge amount of sense to me to use sound to illustrate programming principles such as loops and randomness, as many people are auditory learners.
This kind of thing was incredibly simple with early home computers running Basic, where you could create 4 channel master pieces with ease. I just don't understand why such a thing isn't easily available with Python, which is meant to be a so well suited to learners.
JavaScript now can do this relatively easily with the audio context and its oscillators, but I want to use Python, and in particular to combine the visual power and simplicity of turtle graphics with an auditory component that doesn't require in depth knowledge of computer hardware and physics to produce.
Can anyone help me to find a simple up-to-date (late 2016) solution for this please?

There are various ways to do it. Here is an simple implementation using pyaudio module.
You can install pyaudio using
pip install pyaudio #for windows and
sudo apt-get install python-pyaudio #For linux
Following program has playTone function that gets two inputs; frequency and duarion. You can vary those to get the desired audible frequency tones and "bearable" duration.
If you are planning to create multi-channel complex audio , then you may want to look into pygame. There are ample examples on SO for that.
import pyaudio
import math
def playTone( freq , length):
bit_rate = 16000 #number of frames per second/frameset.
frequency = freq #in Hz, waves per second
play_time = length #in seconds to play sound
if frequency > bit_rate:
bit_rate = frequency+100
num_frames = int(bit_rate * play_time)
total_frames = num_frames % bit_rate
wave_info = ''
for x in xrange(num_frames):
wave_info = wave_info+chr(int(math.sin(x/((bit_rate/frequency)/math.pi))*127+128))
for x in xrange(total_frames):
wave_info = wave_info+chr(128)
p = PyAudio()
stream = p.open(format = p.get_format_from_width(1),
channels = 1,
rate = bit_rate,
output = True)
stream.write(wave_info)
stream.stop_stream()
stream.close()
p.terminate()
if __name__ == '__main__':
frequency = 1500 #Hz
duration = 2 #seconds
PyAudio = pyaudio.PyAudio
#Function to play frequency for given duration
playTone(frequency , duration)

Related

X310 USRP with python

I'm new to USRP so I don't quite understand the transmission and reception. I have a IQ data needs to be transmitted, I'm using the tx_waveform.py to perform the transmission or any other I should use? What would be the output of this? What are the configuration need to be done to transmit the data and receive the IQ data on receiver (OTA or Over the wire)?? What should be the procedure of this? I have attached the example code I found, this would come in receiver part, but how to use the tx_waveform.py? I just need to have a simple end to end transmission setup.
Thank you
I am using the same X310 USRP for the close loop transmission by simply connect a RF cable between them. Besides, I have one octoclock is connected to this USRP.
num_symbols = 10000
r = 0.1*np.random.randn(num_symbols) + 0.1j*np.random.randn(num_symbols)
print(r.size)
r = r.astype(np.complex64) # Convert to 64
r.tofile('test.dat')
import uhd
import numpy as np
usrp = uhd.usrp.MultiUSRP()
num_samps = 10000
center_freq = 1e9
sample_rate = 50e6
gain = 20
usrp.set_rx_rate(sample_rate, 0)
usrp.set_rx_freq(uhd.libpyuhd.types.tune_request(center_freq), 0)
usrp.set_rx_gain(gain, 0)
# Set up the stream and receive buffer
st_args = uhd.usrp.StreamArgs("fc32", "sc16")
st_args.channels = [0]
metadata = uhd.types.RXMetadata()
streamer = usrp.get_rx_stream(st_args)
recv_buffer = np.zeros((1, 1000), dtype=np.complex64) #maximum allowed value is 1996 through streamer.get_max_num_samps()
# Start Stream
stream_cmd = uhd.types.StreamCMD(uhd.types.StreamMode.start_cont)
stream_cmd.stream_now = True
streamer.issue_stream_cmd(stream_cmd)
# Receive Samples
samples = np.fromfile('test.dat', np.complex64)
for i in range(num_samps//1000):
streamer.recv(recv_buffer, metadata)
samples[i*1000:(i+1)*1000] = recv_buffer[0]
# Stop Stream
stream_cmd = uhd.types.StreamCMD(uhd.types.StreamMode.stop_cont)
streamer.issue_stream_cmd(stream_cmd)
print(samples)
Your code looks like it was taken from this source with a few minor modifications: PySDR: A Guide to SDR and DSP using Python
If you look a bit further down on that page, there is an example describing how to transmit data, using the usrp.send_waveform()
Furthermore, the modification you made to that example is a bit strange:
# Receive Samples
samples = np.fromfile('test.dat', np.complex64) #<-- here you populate samples with data from your file
for i in range(num_samps//1000):
streamer.recv(recv_buffer, metadata)
samples[i*1000:(i+1)*1000] = recv_buffer[0] #<-- now you overwrite with received data
First you need to confirm you have uhd package by runing:
python
import uhd
Then you need to confirm your host PC could find your USRP X310 by typing
uhd_find_devices --args addr={your X310''s IP address}
Then you could download latest python examples [tx_waveforms.py,rx_to_file.py] from uhd's repo
Then you could run --help to see if you can understand how to use these two file
python
tx_waveforms.py --help
rx_to_file.py --help
Also it will make you know that you are missing some packages which you need to pip install by yourself.
This page will inspire you how to pass the argument to the program even though it was not using the same file as you downloaded, but the low level API is similar.

How to play a sound onto a input stream

I was wondering if it was possible to play a sound directly into a input from python. I am using linux, and with that I am using OSS, ALSA, and Pulseaudio
You can definitely play (and generate) sound with python
Here is a example code that generates sinewave, opens default Alsa playback device and plays sinewave through that
#!/usr/bin/env python3
import math
import struct
import alsaaudio
from itertools import *
def sine_wave(frequency=440.0, framerate=44100, amplitude=0.5):
"""Stolen from here: http://zacharydenton.com/generate-audio-with-python/"""
period = int(framerate / frequency)
if amplitude > 1.0: amplitude = 1.0
if amplitude < 0.0: amplitude = 0.0
lookup_table = [float(amplitude) * math.sin(2.0*math.pi*float(frequency)*(float(i%period)/float(framerate))) for i in range(period)]
return (lookup_table[i%period] for i in count(0))
sound_out = alsaaudio.PCM() # open default sound output
sound_out.setchannels(1) # use only one channel of audio (aka mono)
sound_out.setrate(44100) # how many samples per second
sound_out.setformat(alsaaudio.PCM_FORMAT_FLOAT_LE) # sample format
for sample in sine_wave():
# alsa only eats binnary data
b = struct.pack("<f", sample) # convert python float to binary float
sound_out.write(b)
or you can loopback microphone to your speakers
#!/usr/bin/env python3
import struct
import alsaaudio
sound_out = alsaaudio.PCM() # open default sound output
sound_out.setchannels(1) # use only one channel of audio (aka mono)
sound_out.setperiodsize(5) # buffer size, default is 32
sound_in = alsaaudio.PCM(type=alsaaudio.PCM_CAPTURE) # default recording device
sound_in.setchannels(1) # use only one channel of audio (aka mono)
sound_in.setperiodsize(5) # buffer size, default is 32
while True:
sample_lenght, sample = sound_in.read()
sound_out.write(sample)
much more examples can be found in python alsaaudio library http://pyalsaaudio.sourceforge.net/libalsaaudio.html
I guess it depends on what you would like to do with it after you got it "into" python.
I would definitely look at the scikits.audiolab library. That's what you might use if you wanted to draw up spectrograms of what ever sound you are trying process (I'm guessing that's what you want to do?).

Real-time procedural sounds with Python?

I want to do procedural sounds in Python, and instantly play them back rather than save them to a file. What should I be using for this? Can I just use built-in modules, or will I need anything extra?
I will probably want to change pitch, volume, things like that.
Using numpy along with scikits.audiolab should do the trick. audiolab has a play function which supports the ALSA and Core Audio backends.
Here's an example of how you might produce a simple sine wave using numpy:
from __future__ import division
import numpy as np
def testsignal(hz,amplitude = .5,seconds=5.,sr=44100.):
'''
Create a sine wave at hz for n seconds
'''
# cycles per sample
cps = hz / sr
# total samples
ts = seconds * sr
return amplitude * np.sin(np.arange(0,ts*cps,cps) * (2*np.pi))
To create five seconds of a sine wave at 440 hz and listen to it, you'd do:
>>> from scikits.audiolab import play
>>> samples = testsignal(440)
>>> play(samples)
Note that play is a blocking call. Control won't be returned to your code until the sound has completed playing.
Check out this Python wiki page. Particularly the "Music programming in Python" section.
Pyglet could be a good option as it embeds functions for audio procedural:
Pyglet/media_procedural

Python: what are the nearest Linux and OS X [edit: macOS] equivalents of winsound.Beep?

If one wishes to beep the speaker on Windows, Python 2 apparently provides a useful function: winsound.Beep(). The neat thing about this function is that it takes arguments specifying the exact frequency and duration of the beep. This is exactly what I want to do, except that I don't use Windows. So...
What are the nearest equivalents of winsound.Beep() for Linux and OS X [edit: macOS], bringing in as few dependencies as possible?
Please note that I want to be able to beep the speaker directly, not to play a sound file. Also, I need to be able to control the frequency and duration of the beep, so curses.beep() and print '\a' won't do. Lastly, I am aware that PyGame provides extensive sound capabilities, but given that I don't require any of PyGame's other functionality, that would seem like using a sledgehammer to crack a nut (and anyway, I'm trying to do away with dependencies as far as possible).
[Edited on 9 Feb 2023 to reflect the fact that OS X was renamed macOS a few years after this question was asked]
winsound is only for windows and I could not find any cross platform way to do this, other than print "/a". However, you cannot set the frequency and duration with this.
However, you can try the os.system command to do the same with the system command beep. Here is a snippet, which defines the function playsound in a platform independent way
try:
import winsound
except ImportError:
import os
def playsound(frequency,duration):
#apt-get install beep
os.system('beep -f %s -l %s' % (frequency,duration))
else:
def playsound(frequency,duration):
winsound.Beep(frequency,duration)
For more info, look at this blog
EDIT: You will need to install the beep package on linux to run the beep command. You can install by giving the command
sudo apt-get install beep
I found a potential solution here:
http://bytes.com/topic/python/answers/25217-beeping-under-linux
It involves writing directly to /dev/audio. Not sure how portable it is or if it even works at all - i'm not on a linux machine atm.
def beep(frequency, amplitude, duration):
sample = 8000
half_period = int(sample/frequency/2)
beep = chr(amplitude)*half_period+chr(0)*half_period
beep *= int(duration*frequency)
audio = file('/dev/audio', 'wb')
audio.write(beep)
audio.close()
This works on mac:
import numpy as np
import simpleaudio as sa
def sound(x,z):
frequency = x # Our played note will be 440 Hz
fs = 44100 # 44100 samples per second
seconds = z # Note duration of 3 seconds
# Generate array with seconds*sample_rate steps, ranging between 0 and seconds
t = np.linspace(0, seconds, seconds * fs, False)
# Generate a 440 Hz sine wave
note = np.sin(frequency * t * 2 * np.pi)
# Ensure that highest value is in 16-bit range
audio = note * (2**15 - 1) / np.max(np.abs(note))
# Convert to 16-bit data
audio = audio.astype(np.int16)
# Start playback
play_obj = sa.play_buffer(audio, 1, 2, fs)
# Wait for playback to finish before exiting
play_obj.wait_done()
sound(300,2)
sound(200,1)
The most light-weight cross-platform layer I can see is "PortAudio". This is used by R for instance in their package to wrap platform-specific driver calls into simple play/record of digitized waveforms as an array.
The good folk at M.I.T. produce a Python binding for this, but you will need to include the compiled .dll/.so for this to work. http://people.csail.mit.edu/hubert/pyaudio/
( libao is similar by Xiph the makers of Ogg/Vorbis , a wrapper pyao exists but this seems less widely used )
SoX is an excellent set of cross-platform tools with much more functionality for format conversion and reading files etc..
Using ctypes to make calls from Python to a driver is feasible but very messy, even the simplest legacy WinMM.
I've found 3 methods for Linux:
new method using the Linux evdev API, works with any user in the input group (example source code)
old method using fcntl and /dev/console (requires root priviledges) (example source code)
invoke the beep command directly with subprocess or os.system (slower and must be installed in the system).
See also my tone() function here with all the alternatives.

Unit Conversion in Python

I'm working on a project that lets users track different data types over time. Part of the base idea is that a user should be able to enter data using any units that they need to. I've been looking at both units:
http://pypi.python.org/pypi/units/
and quantities:
http://pypi.python.org/pypi/quantities/
However I'm not sure the best way to go. From what I can tell, quantities is more complex, but includes a better initial list of units.
I applaud use of explicit units in scientific computing applications. Using explicit units is analogous brushing your teeth. It adds some tedium up front, but the type safety you get can save a lot of trouble in the long run. Like, say, not crashing $125 million orbiters into planets.
You should also probably check out these two other python unit/quantity packages:
Unum
Scientific.Physics.PhysicalQuantity
I once investigated Scientific.Physics.PhysicalQuantity. It did not quite meet my needs, but might satisfy yours. It's hard to tell what features you need from your brief description.
I ended up writing my own python package for unit conversion and dimensional analysis, but it is not properly packaged for release yet. We are using my unit system in the python bindings for our OpenMM system for GPU accelerated molecular mechanics. You can browse the svn repository of my python units code at:
SimTK python units
Eventually I intend to package it for distribution. If you find it interesting, please let me know. That might motivate me to package it up sooner. The features I was looking for when I was designing the SimTK python units system included the following:
Units are NOT necessarily stored in terms of SI units internally. This is very important for me, because one important application area for us is at the molecular scale. Using SI units internally can lead to exponent overflow in commonly used molecular force calculations. Internally, all unit systems are equally fundamental in SimTK.
I wanted similar power and flexibility to the Boost.Units system in C++. Both because I am familiar with that system, and because it was designed under the scrutiny of a large group of brilliant engineers. Boost.Units is a well crafted second generation dimensional analysis system. Thus I might argue that the SimTK units system is a third generation system :). Be aware that while Boost.Units is a "zero overhead" system with no runtime cost, all python quantity implementations, including SimTK units, probably exact a runtime cost.
I want dimensioned Quantities that are compatible with numpy arrays, but do not necessarily require the python numpy package. In other words, Quantities can be based on either numpy arrays or on built in python types.
What features are important to you?
Pint has recently come onto the field. Anybody care to share their experiences? Looks good. FYI: It looks like Pint will be integrated with Uncertainties in the near future.
There is another package called unyt from the yt-project. The authors of unyt acknowledge the existence of Pint and astropy.units. Conversions from and to these other packages is supported.
The selling point of unyt is speed. It is faster than the other two. The unit packages are compared in several benchmarks in this paper.
The benchmarks are disappointing for anyone obsessed with performance. :-( The slowdown of calculations with any of these unit systems is large. The slowdown factor is 6-10 for arrays with 1000 entries (worse for smaller arrays).
Disclaimer: I am not affiliated with unyt, I just want to share what I learned about unit systems.
Note that quantities has very bad support for temperature:
>>> (100 * pq.degC).rescale(pq.degF)
array(179.99999999999997) * degF
>>> (0 * pq.degC).rescale(pq.degF)
array(0.0) * degF
0 degrees Celsius isn't 0 degrees Fahrenheit. Their framework doesn't support any kind of conversion that isn't just multiplying by a factor.
I am surprised that nobody mentioned SymPy yet. SymPy is a mature and well-maintained symbolic mathematics library for Python that is moreover a NumFOCUS-sponsored project.
It has a Physics module with many useful classes and functions for "solving problems in physics". Most relevant for you, it has a Unit sub-module that contains everything you need, I think; just read the excellent documentation.
You may want to look at a new package called natu. It addresses the three issues that #ChristopherBruns listed. It's available in PyPI.
I'm the author of that package, and I'd appreciate any comments or suggestions.
It looks like another package has come out for doing this as well, written by Massimo DiPierro of web2py fame, called Buckingham.
Also of note, Brian has had something like this for some time.
Thought to mention the units package which is part of the Astropy package.
It's well maintained, easy to use, and has all the basic units (as well as astrophysics-related units).
It provides tools for both units and quantities. And there's also a module for physical constants.
I'd like to point to a separate library for dealing with units: Barril
https://github.com/ESSS/barril
Docs at: https://barril.readthedocs.io/en/latest/
While it does have support for creating "random" units from computation (such as Pint, unum, etc), it's more tailored to having a database of units (which the library has by default -- see: https://barril.readthedocs.io/en/latest/units.html and the implementation: https://github.com/ESSS/barril/blob/master/src/barril/units/posc.py) and then you can query and transform based on the related units.
One thing it supports that does a lot of difference in that regard is dealing with unit conversions which would be "dimentionless" -- such as m3/m3 (i.e.:volume per volume) and then converting to cm3/m3 and keeping the dimension.
i.e.: in pint:
>>> import pint
>>> ureg = pint.UnitRegistry()
>>> m = ureg.meter
>>> v = 1 \* (m\*3)/(m\*3)
>>> v
<Quantity(1.0, 'dimensionless')>
And then, after that (as far as I know), it's not really possible to do additional unit conversions properly knowing that it was m3/m3.
In barril:
>>> from barril.units import Scalar
>>> a = Scalar(3, 'm3/m3')
>>> a.GetValue('cm3/m3')
3000000.0
>>> a.category
'volume per volume'
>>> a.unit
'm3/m3'
and something as a.GetValue('m3') (with an invalid value) would give an error saying that the conversion is actually invalid.
The unit database (which was initially based on the POSC Units of Measure Dictionary) is a bit more tailored for the Oil & Gas field, but should be usable outside of it too.
I think you should use quantities, because a quantity has some units associated with it.
Pressure, for example, will be a quantity that could be entered and converted in and to different units (Pa, psi, atm, etc). Probably you could create new quantities specifics for your application.
My preferred package is QuantiPhy. It takes a different approach than most other packages. With QuantiPhy the units are simply strings, and the package is largely used when reading or writing quantities. As such, it much easier to incorporate into your software. QuantiPhy supports unit and scale factor conversion both when creating quantities and when rendering them to strings. Here is an example that reads and then writes a table of times and temperatures, converting from minutes/°F to seconds/K on the way in and back to the original units on the way out:
>>> from quanitphy import Quantity
>>> rawdata = '0 450, 10 400, 20 360'
>>> data = []
>>> for pair in rawdata.split(','):
... time, temp = pair.split()
... time = Quantity(time, 'min', scale='s')
... temp = Quantity(temp, '°F', scale='K')
... data += [(time, temp)]
>>> for time, temp in data:
... print(f'{time:9q} {temp:9q}')
0 s 505.37 K
600 s 477.59 K
1.2 ks 455.37 K
>>> for time, temp in data:
... print(f"{time:<7smin} {temp:s°F}")
0 min 450 °F
10 min 400 °F
20 min 360 °F
I find the units packages to be more than what want. It doesn't take much code to start building your own functions that refer back to the very few basic fundamental numbers. Also, It forces you to do the dimensional analysis to prevent errors.
def FtoC(Tf):
return (Tf-32)*5/9
def CtoF(Tc):
return 9*Tc/5+32
def CtoK(Tc):
return Tc+273.15
def INCHtoCM(Inch):
return 2.54 * Inch
def CMtoINCH(cm):
return cm / INCHtoCM(1)
def INCHtoMETER(inch):
return .01*INCHtoCM(inch)
def FOOTtoMETER(foot):
return INCHtoMETER(12*foot)
def METERtoINCH(Meter):
return CMtoINCH(100 * Meter)
def METERtoFOOT(Meter):
return METERtoINCH(Meter)/12
def M3toINCH3(M3):
return (METERtoINCH(M3))**3
def INCH3toGALLON(Inch3):
return Inch3 / 231
def M3toGALLON(M3):
return INCH3toGALLON(M3toINCH3(M3))
def KG_M3toLB_GALLON(KGperM3):
return KGtoLBM(KGperM3) / M3toGALLON(1)
def BARtoPASCAL(bar):
return 100000 * bar
def KGtoLBM(kilogram):
return kilogram * 2.20462262185
def LBMtoKG(lbm):
return lbm/KGtoLBM(1)
def NEWTONtoLBF(newton):
return newton * KGtoLBM(1) * METERtoFOOT(1) / STANDARD_GRAVITY_IMPERIAL()
def LBFtoNEWTON(lbf):
return lbf * STANDARD_GRAVITY_IMPERIAL() * LBMtoKG(1) * FOOTtoMETER(1)
def STANDARD_GRAVITY_IMPERIAL():
return 32.174049
def STANDARD_GRAVITY_SI():
return 9.80665
def PASCALtoPSI(pascal):
return pascal * NEWTONtoLBF(1) / METERtoINCH(1)**2
def PSItoPASCAL(psi):
return psi * LBFtoNEWTON(1) / INCHtoMETER(1)**2
Then let's say you want to plot the static head pressure of 1,3 Butadiene #44 F and use gauges in PSI because you live in the US but the density tables are in SI units as they should be........................
# butadiene temperature in Fahrenheit
Tf = 44
# DIPPR105 Equation Parameters (Density in kg/m3, T in K)
# valid in temperature 165 to 424 Kelvin
A=66.9883
B=0.272506
C=425.17
D=0.288139
# array of pressures in psi
Pscale = np.arange(0,5,.1, dtype=float)
Tk = CtoK(FtoC(44))
Density = A / (B**(1+(1-Tk/C)**D)) # KG/M3
Height = [PSItoPASCAL(P) / (Density * STANDARD_GRAVITY_SI()) for P in Pscale]
Height_inch = METERtoINCH(1) * np.array(Height, dtype=np.single)
Another package to mention is Axiompy.
Installation: pip install axiompy
from axiompy import Units
units = Units()
print(units.unit_convert(3 * units.metre, units.foot))
>>> <Value (9.84251968503937 <Unit (foot)>)>

Categories

Resources