File size: 7,553 Bytes
0061c9d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
import json,subprocess
import random
from TTS.api import TTS
class VoiceProfile:
    def __init__(self, name, voice):
        self.name = name
        self.voice = voice

    def to_dict(self):
        return {
            'name': self.name,
            'voice': self.voice
        }

    @classmethod
    def from_dict(cls, profile_dict):
        return cls(
            profile_dict['name'],
            profile_dict['voice']
        )

    def configure_tts(self):
        # Set Festival voice
        subprocess.run(["festival", "--tts", "(voice_" + self.voice + ")"])

class VoiceProfileManager:
    def __init__(self, filename="voice_profiles.json"):
        self.filename = filename
        self.profiles = []
        self.load_profiles()

    def load_profiles(self):
        try:
            with open(self.filename, 'r') as file:
                profiles_data = json.load(file)
                self.profiles = [VoiceProfile.from_dict(profile) for profile in profiles_data]
        except FileNotFoundError:
            print(f"File '{self.filename}' not found. Starting with an empty profile list.")
            self.profiles = []

    def save_profiles(self):
        profiles_data = [profile.to_dict() for profile in self.profiles]
        with open(self.filename, 'w') as file:
            json.dump(profiles_data, file, indent=4)
        print(f"Profiles saved to '{self.filename}'.")

    def add_profile(self, profile):
        self.profiles.append(profile)

    def generate_random_profile(self):
        name = f"Profile-{len(self.profiles) + 1}"
        voices = ["cmu_us_slt", "cmu_us_awb", "cmu_us_rms", "cmu_us_bdl"]  # Example Festival voices
        voice = random.choice(voices)
        new_profile = VoiceProfile(name, voice)
        self.add_profile(new_profile)
        return new_profile

    def list_profiles(self):
        if not self.profiles:
            return "No profiles found."
        else:
            profiles_list = []
            for idx, profile in enumerate(self.profiles, start=1):
                profiles_list.append(f"Profile {idx}: {profile.name} - Voice: {profile.voice}")
            return profiles_list

    def get_profile_by_name(self, profile_name):
        for profile in self.profiles:
            if profile.name == profile_name:
                return profile
        return None


class VoiceProfileTool:
    def __init__(self, root):
        self.root = root
        self.root.title("Voice Profile Manager")

        self.profile_manager = VoiceProfileManager()

        self.create_widgets()

    def create_widgets(self):
        # Frame for profile list and operations
        profile_frame = ttk.LabelFrame(self.root, text="Voice Profiles")
        profile_frame.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W+tk.E+tk.N+tk.S)

        # Listbox to display profiles
        self.profiles_listbox = tk.Listbox(profile_frame, width=50, height=10)
        self.profiles_listbox.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W+tk.E+tk.N+tk.S)

        # Scrollbar for the listbox
        scrollbar = ttk.Scrollbar(profile_frame, orient=tk.VERTICAL, command=self.profiles_listbox.yview)
        scrollbar.grid(row=0, column=1, pady=10, sticky=tk.N+tk.S)
        self.profiles_listbox.config(yscrollcommand=scrollbar.set)

        # Button to generate random profile
        generate_btn = ttk.Button(profile_frame, text="Generate Random Profile", command=self.generate_random_profile)
        generate_btn.grid(row=1, column=0, padx=10, pady=5, sticky=tk.W+tk.E)

        # Button to refresh profile list
        refresh_btn = ttk.Button(profile_frame, text="Refresh List", command=self.refresh_profiles_list)
        refresh_btn.grid(row=1, column=1, padx=10, pady=5, sticky=tk.W+tk.E)

        # Frame for TTS operations
        tts_frame = ttk.LabelFrame(self.root, text="Text-to-Speech (TTS)")
        tts_frame.grid(row=1, column=0, padx=10, pady=10, sticky=tk.W+tk.E+tk.N+tk.S)

        # Text entry for TTS input
        ttk.Label(tts_frame, text="Enter text to speak:").grid(row=0, column=0, padx=10, pady=5, sticky=tk.W)
        self.tts_text_entry = ttk.Entry(tts_frame, width=50)
        self.tts_text_entry.grid(row=0, column=1, padx=10, pady=5, sticky=tk.W+tk.E)

        # Combobox to select profile for TTS
        ttk.Label(tts_frame, text="Select profile:").grid(row=1, column=0, padx=10, pady=5, sticky=tk.W)
        self.profile_combobox = ttk.Combobox(tts_frame, width=48, state="readonly")
        self.profile_combobox.grid(row=1, column=1, padx=10, pady=5, sticky=tk.W+tk.E)

        # Button to speak text
        speak_btn = ttk.Button(tts_frame, text="Speak", command=self.speak_text)
        speak_btn.grid(row=2, column=1, padx=10, pady=10, sticky=tk.W+tk.E)

        # Populate initial profiles list
        self.refresh_profiles_list()

    def refresh_profiles_list(self):
        # Clear current listbox and combobox
        self.profiles_listbox.delete(0, tk.END)
        self.profile_combobox['values'] = []

        # Load profiles from manager
        profiles = self.profile_manager.list_profiles()
        if profiles:
            for profile in profiles:
                self.profiles_listbox.insert(tk.END, profile)
                self.profile_combobox['values'] += (profile.split(':')[0],)  # Add profile name to combobox options

    def generate_random_profile(self):
        new_profile = self.profile_manager.generate_random_profile()
        messagebox.showinfo("Profile Generated", f"Generated new profile: {new_profile.name}")
        self.refresh_profiles_list()

    def speak_text(self):
        text_to_speak = self.tts_text_entry.get().strip()
        selected_profile_name = self.profile_combobox.get().strip()

        if not text_to_speak:
            messagebox.showwarning("Input Required", "Please enter text to speak.")
            return

        if not selected_profile_name:
            messagebox.showwarning("Profile Required", "Please select a profile.")
            return

        profile = self.profile_manager.get_profile_by_name(selected_profile_name)
        if profile:
            profile.configure_tts()
            subprocess.Popen(["festival", "--tts"], stdin=subprocess.PIPE).communicate(bytes(text_to_speak, 'utf-8'))
            messagebox.showinfo("Text-to-Speech", f"Text: {text_to_speak}\nProfile: {profile.name}\nVoice: {profile.voice}")
        else:
            messagebox.showerror("Profile Not Found", f"Profile '{selected_profile_name}' not found.")

# Main program
if __name__ == "__main__":
    root = tk.Tk()
    app = VoiceProfileTool(root)
    root.mainloop()
""" Explanation:
Integration with piper_tts: This example uses the TTS class from piper_tts for text-to-speech synthesis. The configure_tts method in VoiceProfile class is used to set parameters (language, pitch, speaking_rate) on the TTS engine before synthesizing speech.

Tkinter GUI: The GUI interface (VoiceProfileTool class) is built using Tkinter widgets (Listbox, Entry, Combobox, Button, etc.) to manage voice profiles (list, generate random profile) and perform TTS (enter text, select profile, speak).

Profile Management: VoiceProfileManager handles loading/saving profiles from/to JSON file, generating random profiles, listing profiles, and retrieving profiles by name.

Handling TTS Output: After synthesizing speech with piper_tts, the example shows a message box with details about the synthesized text and the selected profile.
 """