====== 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 =====
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:**
- The script imports the necessary libraries, including `numpy` for numerical operations and `pyaudio` for audio playback.
2. **Generate Tone:**
- The `generate_tone` function creates a time axis using `numpy.linspace` and then generates a sine wave based on the specified frequency.
- The sine wave is scaled and converted to a 16-bit integer format for compatibility with `pyaudio`.
3. **Initialize PyAudio:**
- `pyaudio.PyAudio()` initializes the audio system.
- The audio stream is opened with the correct format (16-bit, 1 channel, sample rate of 44100 Hz).
4. **Play Tone:**
- The generated tone is played through the default audio output device using `stream.write`.
5. **Cleanup:**
- The audio stream is stopped and closed, and the `PyAudio` instance is terminated to free resources.
6. **Command Line Interface:**
- 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: =====
* To execute the script, run the `tone_generator.py` file with the desired frequency and duration as arguments.
* Ensure that the required dependencies (`numpy`, `pyaudio`) are installed.
* Example usage: `python tone_generator.py 500 5` will generate a 500 Hz tone for 5 seconds.
* Any errors encountered during execution are reported to the user for troubleshooting.
**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!