Table of Contents

Creating a Sine Wave Tone Generator in Python

Objective: The `tone_generator` script aims to generate a sine wave tone of a specified frequency and duration, and play it through the default audio output device.

App

tone_generator.py
import numpy as np
import pyaudio
import argparse
 
def generate_tone(frequency, duration, sample_rate=44100, volume=0.5):
    # Generate the time axis
    t = np.linspace(0, duration, int(sample_rate * duration), False)
    # Generate the sine wave
    tone = volume * np.sin(2 * np.pi * frequency * t)
 
    # Ensure that we have the correct format
    tone = np.int16(tone * 32767)
 
    # Initialize PyAudio
    p = pyaudio.PyAudio()
    stream = p.open(format=pyaudio.paInt16,
                    channels=1,
                    rate=sample_rate,
                    output=True)
 
    # Play the tone
    stream.write(tone.tobytes())
 
    # Cleanup
    stream.stop_stream()
    stream.close()
    p.terminate()
 
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Generate a sine wave tone of a specific frequency.")
    parser.add_argument("frequency", type=float, help="Frequency of the sine wave in Hz.")
    parser.add_argument("duration", type=float, help="Duration of the tone in seconds.")
    args = parser.parse_args()
 
    generate_tone(args.frequency, args.duration)

Script Overview:

- Filename: `tone_generator.py` - Dependencies: `numpy`, `pyaudio` - Functions:

1. `generate_tone(frequency, duration, sample_rate=44100, volume=0.5)`: Generates and plays a sine wave tone of a specified frequency and duration.

Script Execution:

1. Import Dependencies:

  1. The script imports the necessary libraries, including `numpy` for numerical operations and `pyaudio` for audio playback.

2. Generate Tone:

  1. The `generate_tone` function creates a time axis using `numpy.linspace` and then generates a sine wave based on the specified frequency.
  2. The sine wave is scaled and converted to a 16-bit integer format for compatibility with `pyaudio`.

3. Initialize PyAudio:

  1. `pyaudio.PyAudio()` initializes the audio system.
  2. The audio stream is opened with the correct format (16-bit, 1 channel, sample rate of 44100 Hz).

4. Play Tone:

  1. The generated tone is played through the default audio output device using `stream.write`.

5. Cleanup:

  1. The audio stream is stopped and closed, and the `PyAudio` instance is terminated to free resources.

6. Command Line Interface:

  1. The script uses `argparse` to parse command-line arguments for frequency and duration, allowing users to specify these parameters when running the script.

Script Execution:

Final Note: The `tone_generator` script provides a simple and flexible way to generate and play sine wave tones of various frequencies and durations, making it useful for testing audio equipment or creating sound effects.

Plot

In this section, we'll explore how to visualize the generated sine wave tone using matplotlib. Here's the modified script:

import numpy as np
import pyaudio
import matplotlib.pyplot as plt
import argparse
 
def generate_tone(frequency, duration, sample_rate=44100, volume=0.5):
    t = np.linspace(0, duration, int(sample_rate * duration), False)
    tone = volume * np.sin(2 * np.pi * frequency * t)
    tone = np.int16(tone * 32767)
 
    p = pyaudio.PyAudio()
    stream = p.open(format=pyaudio.paInt16,
                    channels=1,
                    rate=sample_rate,
                    output=True)
 
    stream.write(tone.tobytes())
 
    stream.stop_stream()
    stream.close()
    p.terminate()
 
    return t, tone
 
def plot_tone(frequency, duration):
    t, tone = generate_tone(frequency, duration)
    plt.figure(figsize=(10, 4))
    plt.plot(t[:1000], tone[:1000])  # Plot first 1000 samples for clarity
    plt.title(f'Sine Wave - {frequency} Hz')
    plt.xlabel('Time [s]')
    plt.ylabel('Amplitude')
    plt.grid(True)
    plt.show()
 
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Generate and plot a sine wave tone of a specific frequency.")
    parser.add_argument("frequency", type=float, help="Frequency of the sine wave in Hz.")
    parser.add_argument("duration", type=float, help="Duration of the tone in seconds.")
    parser.add_argument("--plot", action="store_true", help="Plot the generated tone.")
    args = parser.parse_args()
 
    if args.plot:
        plot_tone(args.frequency, args.duration)
    else:
        generate_tone(args.frequency, args.duration)

This script will generate the sine wave tone and, if the `–plot` flag is provided, it will also plot the first 1000 samples of the generated tone. Let me know if you need further assistance!