liveflowai 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- liveflowai/__init__.py +0 -0
- liveflowai/__main__.py +5 -0
- liveflowai/audio/__init__.py +0 -0
- liveflowai/audio/audio_file_selector.py +153 -0
- liveflowai/audio/chord_analyzer.py +1342 -0
- liveflowai/audio/tempo_analyzer.py +248 -0
- liveflowai/database/__init__.py +0 -0
- liveflowai/database/database.py +403 -0
- liveflowai/detection/__init__.py +0 -0
- liveflowai/detection/chord_detector.py +1146 -0
- liveflowai/detection/song_predictor.py +753 -0
- liveflowai/main.py +494 -0
- liveflowai/output/__init__.py +0 -0
- liveflowai/output/iem_manager.py +1284 -0
- liveflowai/transition/__init__.py +1 -0
- liveflowai/transition/engine.py +5 -0
- liveflowai-0.1.0.dist-info/METADATA +253 -0
- liveflowai-0.1.0.dist-info/RECORD +20 -0
- liveflowai-0.1.0.dist-info/WHEEL +4 -0
- liveflowai-0.1.0.dist-info/entry_points.txt +3 -0
liveflowai/__init__.py
ADDED
|
File without changes
|
liveflowai/__main__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# src/liveflowai/audio/audio_file_selector.py
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AudioFileSelector:
|
|
7
|
+
"""
|
|
8
|
+
Interactive selector for audio files stored in data/songs/.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
SUPPORTED_EXTENSIONS = {
|
|
12
|
+
".mp3",
|
|
13
|
+
".wav",
|
|
14
|
+
".flac",
|
|
15
|
+
".m4a",
|
|
16
|
+
".aac",
|
|
17
|
+
".ogg",
|
|
18
|
+
".wma",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def __init__(self, base_dir=None):
|
|
22
|
+
"""
|
|
23
|
+
Args:
|
|
24
|
+
base_dir: Project root directory. If None, automatically
|
|
25
|
+
determines the project root.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
if base_dir is None:
|
|
29
|
+
self.project_root = Path(__file__).resolve().parents[3]
|
|
30
|
+
else:
|
|
31
|
+
self.project_root = Path(base_dir).resolve()
|
|
32
|
+
|
|
33
|
+
self.audio_dir = self.project_root / "data" / "songs"
|
|
34
|
+
|
|
35
|
+
def get_audio_files(self):
|
|
36
|
+
"""
|
|
37
|
+
Return all supported audio files in data/songs/.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
if not self.audio_dir.exists():
|
|
41
|
+
print(f"\nAudio directory does not exist:")
|
|
42
|
+
print(f" {self.audio_dir}")
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
audio_files = [
|
|
46
|
+
file
|
|
47
|
+
for file in self.audio_dir.iterdir()
|
|
48
|
+
if file.is_file()
|
|
49
|
+
and file.suffix.lower() in self.SUPPORTED_EXTENSIONS
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
return sorted(audio_files, key=lambda path: path.name.lower())
|
|
53
|
+
|
|
54
|
+
def display_audio_files(self, audio_files):
|
|
55
|
+
"""
|
|
56
|
+
Display all available audio files with numbers.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
print("\n=== Available Audio Files ===")
|
|
60
|
+
|
|
61
|
+
for index, file_path in enumerate(audio_files, start=1):
|
|
62
|
+
print(f"{index}. {file_path.name}")
|
|
63
|
+
|
|
64
|
+
print("=============================")
|
|
65
|
+
|
|
66
|
+
def select_file(self):
|
|
67
|
+
"""
|
|
68
|
+
Show all available audio files and let the user select one.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Path or None
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
audio_files = self.get_audio_files()
|
|
75
|
+
|
|
76
|
+
if not audio_files:
|
|
77
|
+
print("\nNo supported audio files found in:")
|
|
78
|
+
print(f" {self.audio_dir}")
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
self.display_audio_files(audio_files)
|
|
82
|
+
|
|
83
|
+
while True:
|
|
84
|
+
choice = input(
|
|
85
|
+
f"\nSelect an audio file (1-{len(audio_files)}) "
|
|
86
|
+
"or 'q' to cancel: "
|
|
87
|
+
).strip()
|
|
88
|
+
|
|
89
|
+
if choice.lower() == "q":
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
index = int(choice) - 1
|
|
94
|
+
except ValueError:
|
|
95
|
+
print("Invalid input. Please enter a number.")
|
|
96
|
+
continue
|
|
97
|
+
|
|
98
|
+
if 0 <= index < len(audio_files):
|
|
99
|
+
selected_file = audio_files[index]
|
|
100
|
+
|
|
101
|
+
print(f"\nSelected: {selected_file.name}")
|
|
102
|
+
|
|
103
|
+
return selected_file
|
|
104
|
+
|
|
105
|
+
print(
|
|
106
|
+
f"Invalid selection. "
|
|
107
|
+
f"Please enter a number between 1 and {len(audio_files)}."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def ask_continue(self):
|
|
111
|
+
"""
|
|
112
|
+
Ask whether the user wants to select another audio file.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
True -> select another file
|
|
116
|
+
False -> return to startup menu
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
while True:
|
|
120
|
+
choice = input(
|
|
121
|
+
"\nDo you want to select another audio file? (y/n): "
|
|
122
|
+
).strip().lower()
|
|
123
|
+
|
|
124
|
+
if choice in {"y", "yes"}:
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
if choice in {"n", "no"}:
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
print("Please enter 'y' or 'n'.")
|
|
131
|
+
|
|
132
|
+
def select_multiple(self):
|
|
133
|
+
"""
|
|
134
|
+
Allow the user to repeatedly select audio files.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
list[Path]: Selected audio files.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
selected_files = []
|
|
141
|
+
|
|
142
|
+
while True:
|
|
143
|
+
selected_file = self.select_file()
|
|
144
|
+
|
|
145
|
+
if selected_file is None:
|
|
146
|
+
break
|
|
147
|
+
|
|
148
|
+
selected_files.append(selected_file)
|
|
149
|
+
|
|
150
|
+
if not self.ask_continue():
|
|
151
|
+
break
|
|
152
|
+
|
|
153
|
+
return selected_files
|