-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtkinter-only.py
More file actions
145 lines (119 loc) · 4.67 KB
/
tkinter-only.py
File metadata and controls
145 lines (119 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import os
import time
import tkinter as tk
import wave
from tkinter import messagebox
import pyaudio
# --- Recording Configuration ---
CHUNK = 1024 # Buffer size for data (chunk)
FORMAT = pyaudio.paInt16 # 16-bit audio format
CHANNELS = 1 # Mono
RATE = 44100 # Sample rate (standard CD quality)
RECORD_SECONDS = 5 # Recording duration in seconds
APP_TITLE = "Azor Transcriber"
WAVE_OUTPUT_FILENAME = "output/recording.wav"
class AudioRecorderApp:
def __init__(self, master):
self.master = master
master.title(APP_TITLE)
# PyAudio object initialization
self.p = pyaudio.PyAudio()
self.frames = []
self.stream = None
self.recording = False
self.is_pyaudio_initialized = True
# --- GUI Elements ---
self.label = tk.Label(master, text="Ready to record.", font=("Arial", 12))
self.label.pack(pady=20)
self.record_button = tk.Button(
master,
text=f"Record {RECORD_SECONDS} seconds",
command=self.start_recording,
bg="red",
fg="white",
font=("Arial", 14),
)
self.record_button.pack(pady=10)
self.exit_button = tk.Button(master, text="Exit", command=self.on_closing)
self.exit_button.pack(pady=10)
# Ensure cleanup on window close
master.protocol("WM_DELETE_WINDOW", self.on_closing)
def start_recording(self):
"""Starts the audio recording process."""
if self.recording:
return
self.recording = True
self.frames = []
try:
# Open the audio stream
self.stream = self.p.open(
format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK,
)
self.label.config(
text=f"Recording for {RECORD_SECONDS} seconds...", fg="red",
)
self.record_button.config(state=tk.DISABLED)
# Use .after() for non-blocking chunk reading in the Tkinter main loop.
self.start_time = time.time()
self.read_chunk()
except Exception as e:
self.recording = False
self.record_button.config(state=tk.NORMAL)
self.label.config(text="Error! Check microphone/dependencies.", fg="black")
messagebox.showerror(
"Audio Error", f"Could not open microphone stream: {e}",
)
def read_chunk(self):
"""Reads one chunk of audio data and schedules the next call."""
# Only continue reading if recording is active and duration limit is not reached
if self.recording and (time.time() - self.start_time) < RECORD_SECONDS:
data = self.stream.read(CHUNK, exception_on_overflow=False)
self.frames.append(data)
# Schedule the next read based on chunk time to maintain real-time accuracy
self.master.after(int(CHUNK * 1000 / RATE), self.read_chunk)
else:
self.stop_recording()
def stop_recording(self):
"""Stops the stream, saves the file, and resets the GUI."""
if not self.recording:
return
self.recording = False
self.record_button.config(state=tk.NORMAL)
# Stop and close the stream resource
if self.stream:
self.stream.stop_stream()
self.stream.close()
self.stream = None
# Save to WAVE file
try:
with wave.open(WAVE_OUTPUT_FILENAME, "wb") as wf:
wf.setnchannels(CHANNELS)
wf.setsampwidth(self.p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b"".join(self.frames))
self.label.config(text=f"Saved '{WAVE_OUTPUT_FILENAME}'", fg="green")
messagebox.showinfo(
"Success",
f"Recording saved as:\n{os.path.abspath(WAVE_OUTPUT_FILENAME)}",
)
except Exception as e:
self.label.config(text="File save error!", fg="black")
messagebox.showerror("Save Error", f"Failed to save WAVE file: {e}")
def on_closing(self):
"""Handles clean application shutdown, terminating PyAudio."""
# Ensure PyAudio is terminated only when exiting the application
if self.is_pyaudio_initialized and self.p:
self.p.terminate()
self.is_pyaudio_initialized = False # Prevent double termination
self.master.destroy()
# --- Application Startup ---
if __name__ == "__main__":
root = tk.Tk()
# Set fixed window size
root.geometry("400x200")
app = AudioRecorderApp(root)
root.mainloop()