Skip to content

Commit 66e8eb5

Browse files
Merge pull request #25 from gituser12981u2/feature/hot-switch
Implement hot-switching, threading per visualization, and better logging
2 parents b8a8966 + 2e840ba commit 66e8eb5

14 files changed

Lines changed: 197 additions & 198 deletions

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,5 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate
1313
**Describe the solution you'd like**
1414
A clear and concise description of what you want to happen.
1515

16-
**Describe alternatives you've considered**
17-
A clear and concise description of any alternative solutions or features you've considered.
18-
1916
**Additional context**
2017
Add any other context or screenshots about the feature request here.

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Install system dependencies
2525
run: |
2626
sudo apt-get update
27-
sudo apt-get install -y portaudio19-dev
27+
sudo apt-get install -y portaudio19-dev xvfb
2828
2929
- name: Install dependencies
3030
run: |
@@ -34,4 +34,4 @@ jobs:
3434
3535
- name: Run tests
3636
run: |
37-
python -m unittest discover tests
37+
xvfb-run --auto-servernum python -m unittest discover tests

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ nosetests.xml
2929
coverage.xml
3030
*.cover
3131
.hypothesis/
32+
debug.log
3233

3334
# PyCharm
3435
.idea/

README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ A simple, janky, yet charming terminal-based audio visualizer written in Python.
2121

2222
```bash
2323
sudo apt-get update
24+
```
25+
```bash
2426
sudo apt-get install -y portaudio19-dev
2527
```
2628

@@ -52,13 +54,18 @@ Download and install the PortAudio library from [here](https://files.portaudio.c
5254

5355
```bash
5456
python3 -m venv .venv
55-
source .venv/bin/activate # On Windows, use '.venv\Scripts\activate'
57+
```
58+
```bash
59+
source .venv/bin/activate
60+
# On Windows, use '.venv\Scripts\activate'
5661
```
5762

5863
3. Install the dependencies:
5964

6065
```bash
6166
pip install -r requirements.txt
67+
```
68+
```bash
6269
pip install .
6370
```
6471

@@ -84,20 +91,29 @@ Or to run in horizontal mode:
8491
audio-visualizer --mode horizontal-ltr
8592
```
8693

87-
Note: there are two horizontal modes. One that draws bars from left to right (ltr) and one that draws bars from right to left (rtl)
94+
**Note**: there are two horizontal modes. One that draws bars from left to right (ltr) and one that draws bars from right to left (rtl)
95+
96+
### Hotkey mode switcher
97+
98+
Switch to a different view--mode--while already in a visualization.
99+
100+
While running a mode, press **'ctrl+l'** to switch to horizontal ltr mode, **'ctrl+r'** to switch to horizontal rtl mode, or **'ctrl+v'** to switch to vertical mode.
101+
102+
-'ctrl+l': horizontal ltr mode
103+
-'ctrl+r': horizontal rtl mode
104+
-'ctrl+v': vertical mode
88105

89106
### Command Line Options
90107

91108
- `--mode`: Visualization mode('vertical or horizontal). Default is `vertical`. That is if you put no `--mode` option.
92-
- `--alpha`: Smoothing factor for FFT. Default is `0.2`.
109+
- `--alpha`: Smoothing factor for FFT. Default is `0.4`.
93110
- `--chunk`: Number of frames per buffer. Default is `2048`.
94111
- `--rate`: Sampling rate Default is `44100`.
95-
- `--bar_count`: Number of bars in the visualization. Default is `75`.
96112
97113
Example:
98114
99115
```bash
100-
audio-visualizer --mode horizontal-rtl --alpha 0.3 --chunk 1024 --rate 48000 -bar_count 100
116+
audio-visualizer --mode horizontal-rtl --alpha 0.3 --chunk 1024 --rate 48000
101117
```
102118
103119
## Windows Specific Instructions
@@ -167,3 +183,8 @@ This will ensure that autopep8 and flake8 run automatically before each commit.
167183
## License
168184
169185
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
186+
187+
## Contributors
188+
Thank you to the follow people for their contributions to this project:
189+
190+
-[@ohksith](https://github.com/ohksith) - Provided fix for the terminal to clean it self after visualization stopped

ROADMAP.md

Lines changed: 0 additions & 24 deletions
This file was deleted.

audio_visualizer/__init__.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
from audio_visualizer.visualizer import AudioVisualizer
2+
import argparse
23
import logging
4+
import time
35

4-
logging.basicConfig(level=logging.DEBUG)
6+
# Configure logging
7+
logging.basicConfig(level=logging.DEBUG,
8+
format='%(asctime)s - %(levelname)s - %(message)s',
9+
handlers=[
10+
logging.FileHandler("debug.log"),
11+
])
512

613

714
def main():
815
"""Entry point for the audio visualizer command line interface."""
9-
import argparse
1016

1117
parser = argparse.ArgumentParser(description="Terminal Audio Visualizer")
1218
parser.add_argument(
@@ -33,23 +39,23 @@ def main():
3339
default=44100,
3440
help="Sampling rate; default is 44100",
3541
)
36-
parser.add_argument(
37-
"--bar_count",
38-
type=int,
39-
default=75,
40-
help="Number of bars in the visualization; default is 75",
41-
)
4242
args = parser.parse_args()
4343

4444
visualizer = AudioVisualizer(
4545
mode=args.mode,
4646
alpha=args.alpha,
4747
chunk=args.chunk,
4848
rate=args.rate,
49-
bar_count=args.bar_count,
5049
)
5150
visualizer.start()
5251

52+
try:
53+
while True:
54+
time.sleep(1) # Keep the main thread active
55+
except KeyboardInterrupt:
56+
visualizer.stop()
57+
print("Visualization stopped by user")
58+
5359

5460
if __name__ == '__main__':
5561
main()

audio_visualizer/horizontal_left_to_right_visualizer.py

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212

1313

1414
def visualize_horizontal_left_to_right(
15-
stream, chunk, rate, alpha, bar_count, window, smoothed_fft):
15+
stream, chunk, rate, alpha, window, smoothed_fft, stop_event):
1616
# Initialize smoothed FFT with zeros
1717
smoothed_fft = np.zeros(chunk // 2 + 1)
1818

19-
while True:
19+
while not stop_event.is_set():
2020
data = stream.read_data()
2121
if data is None:
2222
continue
@@ -44,53 +44,3 @@ def visualize_horizontal_left_to_right(
4444
print('\n'.join(frame_buffer), end='', flush=True)
4545

4646
time.sleep(0.1) # control frame rate
47-
48-
49-
# def visualize_horizontal(
50-
# stream, chunk, rate, alpha, bar_count, window, smoothed_fft):
51-
# """
52-
# Visualizes audio data in a vertical bar chart from bottom to top.
53-
# """
54-
# rows, cols = os.get_terminal_size() # Get terminal size dynamically
55-
# bar_count = rows # Assume bar_count should use all available rows
56-
57-
# while True:
58-
# data = stream.read_data()
59-
# if data is None:
60-
# break
61-
# data = np.frombuffer(data, dtype=np.int16)
62-
# data = data.reshape(-1, 2).mean(axis=1) # Average two channels
63-
64-
# windowed_data = data * window
65-
# fft = np.abs(np.fft.fft(windowed_data).real)
66-
# [:len(windowed_data) // 2]
67-
68-
# smoothed_fft = alpha * smoothed_fft + (1 - alpha) * fft
69-
# max_fft = max(np.max(smoothed_fft), 1) # Normalize the max value
70-
71-
# indices = np.logspace(0, np.log10(len(smoothed_fft)),
72-
# num=bar_count + 1,
73-
# endpoint=True, base=10).astype(int)
74-
# indices = np.unique(np.clip(indices, 0, len(smoothed_fft) - 1))
75-
76-
# current_frame = {}
77-
# for i in range(len(indices) - 1):
78-
# bar_values = smoothed_fft[indices[i]:indices[i + 1]]
79-
# bar_value = np.average(bar_values, weights=np.linspace(
80-
# 1, 0.1, num=len(bar_values))) if bar_values.size > 0 else 0
81-
# num_chars = int((bar_value / max_fft) * cols)
82-
83-
# for j in range(cols - num_chars, cols):
84-
# current_frame[(i, j)] = '█'
85-
86-
# frame_buffer = [' ' * rows for _ in range(cols)]
87-
# for x in range(cols): # Iterate over each bar
88-
# for y in range(rows): # Iterate over each character in the bar
89-
# if (x, y) in current_frame:
90-
# frame_buffer[x] = frame_buffer[x][:y] + \
91-
# current_frame[(x, y)] + frame_buffer[x][y+1:]
92-
93-
# os.system('cls' if os.name == 'nt' else 'clear')
94-
# print('\n'.join(frame_buffer), end="", flush=True)
95-
96-
# time.sleep(0.1)

audio_visualizer/horizontal_right_to_left_visualizer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414

1515
def visualize_horizontal_right_to_left(
16-
stream, chunk, rate, alpha, bar_count, window, smoothed_fft):
16+
stream, chunk, rate, alpha, window, smoothed_fft, stop_event):
1717
# Initialize smoothed FFT with zeros
1818
smoothed_fft = np.zeros(chunk // 2 + 1)
1919

20-
while True:
20+
while not stop_event.is_set():
2121
data = stream.read_data()
2222
if data is None:
2323
continue

audio_visualizer/vertical_visualizer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212

1313

1414
def visualize_vertical(
15-
stream, chunk, rate, alpha, bar_count, window, smoothed_fft):
15+
stream, chunk, rate, alpha, window, smoothed_fft, stop_event):
1616
# Initialize smoothed FFT with zeros
1717
smoothed_fft = np.zeros(chunk // 2 + 1)
1818

19-
while True:
19+
while not stop_event.is_set():
2020
data = stream.read_data()
2121
if data is None:
2222
continue
@@ -47,7 +47,7 @@ def visualize_vertical(
4747

4848
time.sleep(0.1) # control frame rate
4949

50-
50+
# Old logic
5151
# def visualize_vertical(
5252
# stream, chunk, rate, alpha, bar_count, window, smoothed_fft):
5353
# """

0 commit comments

Comments
 (0)