Showing
12 changed files
with
542 additions
and
89 deletions
find_peak copy.py
0 → 100644
1 | +import pyaudio | ||
2 | +import numpy as np | ||
3 | +import scipy.signal as signal | ||
4 | +import pydub | ||
5 | +import time | ||
6 | +import librosa | ||
7 | +import tkinter as tk | ||
8 | + | ||
9 | +ORIGIN_SOUND = np.frombuffer(pydub.AudioSegment.from_mp3("./sounds/ping.mp3").raw_data, dtype=np.int16) | ||
10 | + | ||
11 | +# 파라미터 설정 | ||
12 | +RATE = 44100 # 샘플링 주파수 | ||
13 | +CHUNK = 1024 # 읽을 샘플의 수 | ||
14 | +THRESHOLD = 256 # 피크를 검출하기 위한 threshold 값 | ||
15 | +WIN_SIZE = 1024 # STFT를 적용할 윈도우 사이즈 | ||
16 | +HOP_SIZE = 512 # STFT에서 윈도우 사이의 거리 (오버랩 사이즈) | ||
17 | +DELAY = 0.1 # Delay time in seconds | ||
18 | +MAX_FREQ = 3000 # max freq for pitch shifting | ||
19 | +MAX_HEIGHT = 2000 # max height for pitch shifting | ||
20 | + | ||
21 | +sound_idx = 0 | ||
22 | + | ||
23 | +window = tk.Tk() | ||
24 | +window.title("Sound Effect") | ||
25 | +window.geometry("640x400+100+100") | ||
26 | +window.resizable(False, False) | ||
27 | + | ||
28 | +info_text = tk.StringVar() | ||
29 | +info_text.set("welcome! please press record button.") | ||
30 | + | ||
31 | +info_label = tk.Button(window, textvariable=info_text, foreground="black", background="white") | ||
32 | +info_label.pack() | ||
33 | + | ||
34 | +def set_source_mode(mode): | ||
35 | + global SOURCE_MODE | ||
36 | + SOURCE_MODE = mode | ||
37 | + | ||
38 | +# 사용자의 목소리를 duration 초간 녹음. | ||
39 | +def get_user_audio(duration): | ||
40 | + global info_text, info_label | ||
41 | + frames = [] | ||
42 | + p = pyaudio.PyAudio() | ||
43 | + | ||
44 | + # 카운터 시작 | ||
45 | + | ||
46 | + info_text.set("ready for recording...") | ||
47 | + for _ in range(3, 0, -1): | ||
48 | + info_text.set(str(_)) | ||
49 | + time.sleep(1) | ||
50 | + info_text.set("start...") | ||
51 | + | ||
52 | + # 실제 녹음 콜백 함수 | ||
53 | + def add_to_frame(in_data, frame_count, time_info, status): | ||
54 | + frames.append(np.frombuffer(in_data, dtype=np.int16)) | ||
55 | + if(len(frames) < RATE/CHUNK * duration): | ||
56 | + return (in_data, pyaudio.paContinue) | ||
57 | + return (in_data, pyaudio.paComplete) | ||
58 | + | ||
59 | + # 녹음 진행 | ||
60 | + stream = p.open(format=pyaudio.paInt16, channels=1, rate=RATE, input=True, frames_per_buffer=CHUNK, input_device_index=1, stream_callback=add_to_frame) | ||
61 | + | ||
62 | + time.sleep(1) | ||
63 | + stream.start_stream() | ||
64 | + | ||
65 | + sound = np.frombuffer(b''.join(frames), dtype=np.int16) | ||
66 | + | ||
67 | + # stream및 객체들 정리 | ||
68 | + stream.stop_stream() | ||
69 | + stream.close() | ||
70 | + p.terminate() | ||
71 | + | ||
72 | + return sound | ||
73 | + | ||
74 | +def record(): | ||
75 | + global ORIGIN_SOUND | ||
76 | + global SOURCE_MODE | ||
77 | + ORIGIN_SOUND = get_user_audio(0.5) | ||
78 | + SOURCE_MODE = "decibel" # decibel or frequency | ||
79 | + | ||
80 | +def start(): | ||
81 | + global MODE, SOUND_SIZE, sound_idx, sound | ||
82 | + MODE = "high_filter" # echo or pitch_shift | ||
83 | + SOUND_SIZE = len(ORIGIN_SOUND) # 음원 길이 | ||
84 | + | ||
85 | + sound = ORIGIN_SOUND.copy() | ||
86 | + | ||
87 | + print(type(sound), len(sound)) | ||
88 | + | ||
89 | + p = pyaudio.PyAudio() | ||
90 | + | ||
91 | + last_frame = 0 | ||
92 | + | ||
93 | + # 콜백 함수 정의 | ||
94 | + def process_audio(in_data, frame_count, time_info, status): | ||
95 | + | ||
96 | + | ||
97 | + def get_distortion(height, frequency): | ||
98 | + height = min(height, MAX_HEIGHT) / MAX_HEIGHT | ||
99 | + frequency = min(frequency, MAX_FREQ) / MAX_FREQ | ||
100 | + | ||
101 | + if SOURCE_MODE == "decibel": | ||
102 | + param = height | ||
103 | + elif SOURCE_MODE == "frequency": | ||
104 | + param = frequency | ||
105 | + else: | ||
106 | + return ORIGIN_SOUND | ||
107 | + | ||
108 | + if MODE == "pitch_shift": | ||
109 | + return shift_pitch(param) | ||
110 | + elif MODE == "echo": | ||
111 | + return add_echo(param) | ||
112 | + elif MODE == "low_filter": | ||
113 | + return low_filter(param) | ||
114 | + else: | ||
115 | + return ORIGIN_SOUND | ||
116 | + | ||
117 | + def add_echo(decay): | ||
118 | + # Create an empty array to store the echoed audio samples | ||
119 | + echoed_samples = np.zeros_like(ORIGIN_SOUND, dtype=np.int16) | ||
120 | + | ||
121 | + # Calculate the delay in samples | ||
122 | + delay_samples = int(DELAY * 44100) # Assuming a sample rate of 44100 Hz | ||
123 | + | ||
124 | + # Apply the echo effect | ||
125 | + for i in range(delay_samples, len(ORIGIN_SOUND)): | ||
126 | + echoed_samples[i] = ORIGIN_SOUND[i] + int(decay * echoed_samples[i - delay_samples]) | ||
127 | + | ||
128 | + return echoed_samples | ||
129 | + | ||
130 | + def shift_pitch(frequency): | ||
131 | + pitch_shift_factor = frequency | ||
132 | + audio_array = ORIGIN_SOUND.copy() | ||
133 | + # Resample the audio array to change the pitch | ||
134 | + resampled_array = librosa.effects.pitch_shift(np.array(audio_array, dtype=np.float32), sr=RATE, n_steps=pitch_shift_factor, bins_per_octave=1) | ||
135 | + return np.array(resampled_array, dtype=np.int16) | ||
136 | + | ||
137 | + def low_filter(param): | ||
138 | + audio_data = data | ||
139 | + # Define the filter parameters | ||
140 | + cutoff_freq = param * MAX_FREQ # Frequency cutoff for the low-pass filter (in Hz) | ||
141 | + nyquist_freq = 0.5 * RATE # Nyquist frequency (half of the sampling rate) | ||
142 | + normalized_cutoff = cutoff_freq / nyquist_freq # Normalized cutoff frequency | ||
143 | + | ||
144 | + # Design the low-pass filter | ||
145 | + b, a = signal.butter(4, normalized_cutoff, btype='low', analog=False, output='ba') | ||
146 | + | ||
147 | + # Apply the low-pass filter to the audio data | ||
148 | + filtered_audio = signal.lfilter(b, a, audio_data) | ||
149 | + | ||
150 | + return filtered_audio | ||
151 | + | ||
152 | + # 오디오 데이터 변환 | ||
153 | + data = np.frombuffer(in_data, dtype=np.int16) | ||
154 | + | ||
155 | + # STFT 수행 | ||
156 | + f, t, Zxx = signal.stft(data, RATE, nperseg=WIN_SIZE, noverlap=HOP_SIZE) | ||
157 | + | ||
158 | + # 피크 검출 | ||
159 | + peaks, _ = signal.find_peaks(np.abs(np.mean(Zxx, axis=1)), height=THRESHOLD, distance=WIN_SIZE) | ||
160 | + # 파라미터 추정 | ||
161 | + if len(peaks) > 0 and last_frame+1 != frame_count: | ||
162 | + last_frame = frame_count | ||
163 | + peak_idx = peaks[0] # 첫 번째 피크 선택 | ||
164 | + height = np.abs(Zxx[peak_idx, 0]) # 피크의 높이 추정 | ||
165 | + freq = f[peak_idx] # 피크의 주파수 추정 | ||
166 | + amp = np.max(np.abs(data)) # 신호의 진폭 추정 | ||
167 | + decibel = np.mean(librosa.amplitude_to_db(np.abs(Zxx))) # 진폭을 데시벨로 변환 | ||
168 | + | ||
169 | + if(decibel > 20): | ||
170 | + print("Height: {:.2f}, 주파수: {:.2f}, Amplitude: {:.2f}, Decibel: {:.2f}".format(height, freq, amp, decibel)) | ||
171 | + new_sound = get_distortion(height, freq) | ||
172 | + if(sound_idx > len(sound)): | ||
173 | + sound_idx = 0 | ||
174 | + else: | ||
175 | + mixed_end = min(len(sound), sound_idx + len(new_sound)) | ||
176 | + print(mixed_end, sound_idx) | ||
177 | + sound[sound_idx:mixed_end] = new_sound[:mixed_end-sound_idx] + sound[sound_idx:mixed_end] | ||
178 | + if(mixed_end-sound_idx < len(new_sound)): | ||
179 | + result = np.concatenate((sound, new_sound[mixed_end-sound_idx:]),axis=0) | ||
180 | + sound = result | ||
181 | + elif len(peaks) > 0: | ||
182 | + last_frame = frame_count | ||
183 | + | ||
184 | + sound_idx += 1024 | ||
185 | + if sound_idx > len(sound): | ||
186 | + sound = ORIGIN_SOUND.copy() | ||
187 | + return (np.zeros(data.shape), pyaudio.paContinue) | ||
188 | + return (sound[sound_idx-1024:sound_idx], pyaudio.paContinue) | ||
189 | + | ||
190 | + | ||
191 | + # 입력 스트림 열기 | ||
192 | + stream = p.open(format=p.get_format_from_width(2), | ||
193 | + channels=1, | ||
194 | + rate=RATE, | ||
195 | + input_device_index=1, | ||
196 | + output_device_index=2, | ||
197 | + input=True, | ||
198 | + output=True, | ||
199 | + frames_per_buffer=CHUNK, | ||
200 | + stream_callback=process_audio | ||
201 | + ) | ||
202 | + | ||
203 | + # 스트림 시작 | ||
204 | + stream.start_stream() | ||
205 | + | ||
206 | + | ||
207 | + | ||
208 | + # 프로그램 실행 중지 전까지 무한 대기 | ||
209 | + while stream.is_active(): | ||
210 | + pass | ||
211 | + | ||
212 | + | ||
213 | + # 스트림과 PyAudio 객체 종료 | ||
214 | + stream.stop_stream() | ||
215 | + stream.close() | ||
216 | + p.terminate() | ||
217 | + | ||
218 | + | ||
219 | +record_button = tk.Button(window, text="Record", width=10, height=2, command=lambda: record()) | ||
220 | +record_button.pack() | ||
221 | + | ||
222 | +decibel_button = tk.Button(window, text="Decibel", width=10, height=2, command=lambda: set_source_mode("decibel")) | ||
223 | +decibel_button.pack() | ||
224 | + | ||
225 | +frequency_button = tk.Button(window, text="Frequency", width=10, height=2, command = lambda: set_source_mode("frequency")) | ||
226 | +frequency_button.pack() | ||
227 | + | ||
228 | +start_button = tk.Button(window, text="Start", width=10, height=2, command=lambda: start()) | ||
229 | +start_button.pack() | ||
230 | + | ||
231 | + | ||
232 | +window.mainloop() |
1 | import pyaudio | 1 | import pyaudio |
2 | import numpy as np | 2 | import numpy as np |
3 | import scipy.signal as signal | 3 | import scipy.signal as signal |
4 | -import matplotlib.pyplot as plt | 4 | +import pydub |
5 | +import time | ||
6 | +import librosa | ||
7 | +import tkinter as tk | ||
8 | + | ||
9 | +ORIGIN_SOUND = np.frombuffer(pydub.AudioSegment.from_mp3("./sounds/ping.mp3").raw_data, dtype=np.int16) | ||
10 | + | ||
5 | # 파라미터 설정 | 11 | # 파라미터 설정 |
6 | RATE = 44100 # 샘플링 주파수 | 12 | RATE = 44100 # 샘플링 주파수 |
7 | CHUNK = 1024 # 읽을 샘플의 수 | 13 | CHUNK = 1024 # 읽을 샘플의 수 |
8 | THRESHOLD = 256 # 피크를 검출하기 위한 threshold 값 | 14 | THRESHOLD = 256 # 피크를 검출하기 위한 threshold 값 |
9 | WIN_SIZE = 1024 # STFT를 적용할 윈도우 사이즈 | 15 | WIN_SIZE = 1024 # STFT를 적용할 윈도우 사이즈 |
10 | HOP_SIZE = 512 # STFT에서 윈도우 사이의 거리 (오버랩 사이즈) | 16 | HOP_SIZE = 512 # STFT에서 윈도우 사이의 거리 (오버랩 사이즈) |
17 | +DELAY = 0.1 # Delay time in seconds | ||
18 | +MAX_FREQ = 3000 # max freq for pitch shifting | ||
19 | +MAX_HEIGHT = 2000 # max height for pitch shifting | ||
20 | + | ||
21 | +sound_idx = 0 | ||
22 | + | ||
23 | + | ||
24 | +# 사용자의 목소리를 duration 초간 녹음. | ||
25 | +def get_user_audio(duration): | ||
26 | + | ||
27 | + frames = [] | ||
28 | + p = pyaudio.PyAudio() | ||
29 | + | ||
30 | + # 카운터 시작 | ||
31 | + print("ready for recording...") | ||
32 | + for _ in range(3, 0, -1): | ||
33 | + print(_) | ||
34 | + time.sleep(1) | ||
35 | + print("start...") | ||
36 | + | ||
37 | + # 실제 녹음 콜백 함수 | ||
38 | + def add_to_frame(in_data, frame_count, time_info, status): | ||
39 | + frames.append(np.frombuffer(in_data, dtype=np.int16)) | ||
40 | + if(len(frames) < RATE/CHUNK * duration): | ||
41 | + return (in_data, pyaudio.paContinue) | ||
42 | + return (in_data, pyaudio.paComplete) | ||
43 | + | ||
44 | + # 녹음 진행 | ||
45 | + stream = p.open(format=pyaudio.paInt16, channels=1, rate=RATE, input=True, frames_per_buffer=CHUNK, input_device_index=1, stream_callback=add_to_frame) | ||
46 | + | ||
47 | + time.sleep(1) | ||
48 | + stream.start_stream() | ||
49 | + | ||
50 | + sound = np.frombuffer(b''.join(frames), dtype=np.int16) | ||
51 | + | ||
52 | + # stream및 객체들 정리 | ||
53 | + stream.stop_stream() | ||
54 | + stream.close() | ||
55 | + p.terminate() | ||
56 | + | ||
57 | + return sound | ||
58 | + | ||
59 | +ORIGIN_SOUND = get_user_audio(0.5) | ||
60 | +SOURCE_MODE = "decibel" # decibel or frequency | ||
61 | +MODE = "high_filter" # echo or pitch_shift | ||
62 | +SOUND_SIZE = len(ORIGIN_SOUND) # 음원 길이 | ||
63 | + | ||
64 | +sound = ORIGIN_SOUND.copy() | ||
65 | + | ||
66 | +print(type(sound), len(sound)) | ||
11 | 67 | ||
12 | -# PyAudio 객체 생성 | ||
13 | p = pyaudio.PyAudio() | 68 | p = pyaudio.PyAudio() |
14 | 69 | ||
70 | +last_frame = 0 | ||
71 | + | ||
15 | # 콜백 함수 정의 | 72 | # 콜백 함수 정의 |
16 | def process_audio(in_data, frame_count, time_info, status): | 73 | def process_audio(in_data, frame_count, time_info, status): |
74 | + global buffer | ||
75 | + global sound | ||
76 | + global sound_idx | ||
77 | + global last_frame | ||
78 | + | ||
79 | + | ||
80 | + def get_distortion(height, frequency): | ||
81 | + height = min(height, MAX_HEIGHT) / MAX_HEIGHT | ||
82 | + frequency = min(frequency, MAX_FREQ) / MAX_FREQ | ||
83 | + | ||
84 | + if SOURCE_MODE == "decibel": | ||
85 | + param = height | ||
86 | + elif SOURCE_MODE == "frequency": | ||
87 | + param = frequency | ||
88 | + else: | ||
89 | + return ORIGIN_SOUND | ||
90 | + | ||
91 | + if MODE == "pitch_shift": | ||
92 | + return shift_pitch(param) | ||
93 | + elif MODE == "echo": | ||
94 | + return add_echo(param) | ||
95 | + elif MODE == "low_filter": | ||
96 | + return low_filter(param) | ||
97 | + return ORIGIN_SOUND | ||
98 | + | ||
99 | + def add_echo(decay): | ||
100 | + # Create an empty array to store the echoed audio samples | ||
101 | + echoed_samples = np.zeros_like(ORIGIN_SOUND, dtype=np.int16) | ||
102 | + | ||
103 | + # Calculate the delay in samples | ||
104 | + delay_samples = int(DELAY * 44100) # Assuming a sample rate of 44100 Hz | ||
105 | + | ||
106 | + # Apply the echo effect | ||
107 | + for i in range(delay_samples, len(ORIGIN_SOUND)): | ||
108 | + echoed_samples[i] = ORIGIN_SOUND[i] + int(decay * echoed_samples[i - delay_samples]) | ||
109 | + | ||
110 | + return echoed_samples | ||
111 | + | ||
112 | + def shift_pitch(frequency): | ||
113 | + pitch_shift_factor = frequency | ||
114 | + audio_array = ORIGIN_SOUND.copy() | ||
115 | + # Resample the audio array to change the pitch | ||
116 | + resampled_array = librosa.effects.pitch_shift(np.array(audio_array, dtype=np.float32), sr=RATE, n_steps=pitch_shift_factor, bins_per_octave=1) | ||
117 | + return np.array(resampled_array, dtype=np.int16) | ||
118 | + | ||
119 | + def low_filter(param): | ||
120 | + audio_data = data | ||
121 | + # Define the filter parameters | ||
122 | + cutoff_freq = param * MAX_FREQ # Frequency cutoff for the low-pass filter (in Hz) | ||
123 | + nyquist_freq = 0.5 * RATE # Nyquist frequency (half of the sampling rate) | ||
124 | + normalized_cutoff = cutoff_freq / nyquist_freq # Normalized cutoff frequency | ||
125 | + | ||
126 | + # Design the low-pass filter | ||
127 | + b, a = signal.butter(4, normalized_cutoff, btype='low', analog=False, output='ba') | ||
128 | + | ||
129 | + # Apply the low-pass filter to the audio data | ||
130 | + filtered_audio = signal.lfilter(b, a, audio_data) | ||
131 | + | ||
132 | + return filtered_audio | ||
133 | + | ||
17 | # 오디오 데이터 변환 | 134 | # 오디오 데이터 변환 |
18 | data = np.frombuffer(in_data, dtype=np.int16) | 135 | data = np.frombuffer(in_data, dtype=np.int16) |
19 | 136 | ||
... | @@ -23,23 +140,42 @@ def process_audio(in_data, frame_count, time_info, status): | ... | @@ -23,23 +140,42 @@ def process_audio(in_data, frame_count, time_info, status): |
23 | # 피크 검출 | 140 | # 피크 검출 |
24 | peaks, _ = signal.find_peaks(np.abs(np.mean(Zxx, axis=1)), height=THRESHOLD, distance=WIN_SIZE) | 141 | peaks, _ = signal.find_peaks(np.abs(np.mean(Zxx, axis=1)), height=THRESHOLD, distance=WIN_SIZE) |
25 | # 파라미터 추정 | 142 | # 파라미터 추정 |
26 | - if len(peaks) > 0: | 143 | + if len(peaks) > 0 and last_frame+1 != frame_count: |
144 | + last_frame = frame_count | ||
27 | peak_idx = peaks[0] # 첫 번째 피크 선택 | 145 | peak_idx = peaks[0] # 첫 번째 피크 선택 |
28 | height = np.abs(Zxx[peak_idx, 0]) # 피크의 높이 추정 | 146 | height = np.abs(Zxx[peak_idx, 0]) # 피크의 높이 추정 |
29 | freq = f[peak_idx] # 피크의 주파수 추정 | 147 | freq = f[peak_idx] # 피크의 주파수 추정 |
30 | amp = np.max(np.abs(data)) # 신호의 진폭 추정 | 148 | amp = np.max(np.abs(data)) # 신호의 진폭 추정 |
31 | - progress = (peak_idx + HOP_SIZE) / RATE # 충돌음의 진행 길이 추정 | 149 | + decibel = np.mean(librosa.amplitude_to_db(np.abs(Zxx))) # 진폭을 데시벨로 변환 |
150 | + | ||
151 | + if(decibel > 20): | ||
152 | + print("Height: {:.2f}, 주파수: {:.2f}, Amplitude: {:.2f}, Decibel: {:.2f}".format(height, freq, amp, decibel)) | ||
153 | + new_sound = get_distortion(height, freq) | ||
154 | + if(sound_idx > len(sound)): | ||
155 | + sound_idx = 0 | ||
156 | + else: | ||
157 | + mixed_end = min(len(sound), sound_idx + len(new_sound)) | ||
158 | + print(mixed_end, sound_idx) | ||
159 | + sound[sound_idx:mixed_end] = new_sound[:mixed_end-sound_idx] + sound[sound_idx:mixed_end] | ||
160 | + if(mixed_end-sound_idx < len(new_sound)): | ||
161 | + result = np.concatenate((sound, new_sound[mixed_end-sound_idx:]),axis=0) | ||
162 | + sound = result | ||
163 | + elif len(peaks) > 0: | ||
164 | + last_frame = frame_count | ||
32 | 165 | ||
33 | - # 결과 출력 | 166 | + sound_idx += 1024 |
34 | - print("Height: {:.2f}, Frequency: {:.2f}, Amplitude: {:.2f}, Progress: {:.2f}".format(height, freq, amp, progress)) | 167 | + if sound_idx > len(sound): |
168 | + sound = ORIGIN_SOUND.copy() | ||
169 | + return (np.zeros(data.shape), pyaudio.paContinue) | ||
170 | + return (sound[sound_idx-1024:sound_idx], pyaudio.paContinue) | ||
35 | 171 | ||
36 | - # 반환할 데이터 없음 | ||
37 | - return (in_data, pyaudio.paContinue) | ||
38 | 172 | ||
39 | # 입력 스트림 열기 | 173 | # 입력 스트림 열기 |
40 | stream = p.open(format=p.get_format_from_width(2), | 174 | stream = p.open(format=p.get_format_from_width(2), |
41 | channels=1, | 175 | channels=1, |
42 | rate=RATE, | 176 | rate=RATE, |
177 | + input_device_index=1, | ||
178 | + output_device_index=2, | ||
43 | input=True, | 179 | input=True, |
44 | output=True, | 180 | output=True, |
45 | frames_per_buffer=CHUNK, | 181 | frames_per_buffer=CHUNK, |
... | @@ -49,6 +185,8 @@ stream = p.open(format=p.get_format_from_width(2), | ... | @@ -49,6 +185,8 @@ stream = p.open(format=p.get_format_from_width(2), |
49 | # 스트림 시작 | 185 | # 스트림 시작 |
50 | stream.start_stream() | 186 | stream.start_stream() |
51 | 187 | ||
188 | + | ||
189 | + | ||
52 | # 프로그램 실행 중지 전까지 무한 대기 | 190 | # 프로그램 실행 중지 전까지 무한 대기 |
53 | while stream.is_active(): | 191 | while stream.is_active(): |
54 | pass | 192 | pass | ... | ... |
gui.py
0 → 100644
1 | +import tkinter as tk | ||
2 | + | ||
3 | + | ||
4 | +def clear_row(button, buttons): | ||
5 | + button_row = buttons[:3] if button in buttons[:3] else buttons[3:] | ||
6 | + | ||
7 | + for button in button_row: | ||
8 | + button.config(text='OFF') | ||
9 | + | ||
10 | +def toggle_button(button): | ||
11 | + global buttons | ||
12 | + if button['text'] == 'ON': | ||
13 | + button.config(text='OFF') | ||
14 | + else: | ||
15 | + clear_row(button, buttons) | ||
16 | + button.config(text='ON') | ||
17 | + | ||
18 | +def get_states(): | ||
19 | + global buttons | ||
20 | + for i in range(3): | ||
21 | + if buttons[i].cget('text') == 'ON': | ||
22 | + mode = i | ||
23 | + mode = 0 | ||
24 | + | ||
25 | + for i in range(3, 6): | ||
26 | + if buttons[i].cget('text') == 'ON': | ||
27 | + distortion = i - 3 | ||
28 | + distortion = 0 | ||
29 | + | ||
30 | + return mode, distortion | ||
31 | + | ||
32 | + | ||
33 | + | ||
34 | +# Create the Tkinter window | ||
35 | +window = tk.Tk() | ||
36 | +window.title("Toggle Buttons") | ||
37 | + | ||
38 | +# Create two frames for two rows | ||
39 | +frame1 = tk.Frame(window) | ||
40 | +frame1.pack(side=tk.TOP) | ||
41 | + | ||
42 | +frame2 = tk.Frame(window) | ||
43 | +frame2.pack(side=tk.TOP) | ||
44 | + | ||
45 | +# Create six toggle buttons in two rows | ||
46 | +buttons = [] | ||
47 | +for i in range(6): | ||
48 | + if i < 3: | ||
49 | + frame = frame1 | ||
50 | + else: | ||
51 | + frame = frame2 | ||
52 | + | ||
53 | + button = tk.Button(frame, text='OFF', width=10) | ||
54 | + button.config(command=lambda button=button: toggle_button(button)) | ||
55 | + button.pack(side=tk.LEFT) | ||
56 | + buttons.append(button) | ||
57 | + | ||
58 | +# Start the Tkinter event loop | ||
59 | +window.mainloop() |
pitch_shifting.py
0 → 100644
1 | +import pyaudio | ||
2 | +import numpy as np | ||
3 | + | ||
4 | +# Create an instance of the PyAudio class | ||
5 | +audio = pyaudio.PyAudio() | ||
6 | + | ||
7 | +# Define the desired pitch shift factor | ||
8 | +pitch_shift_factor = 1.5 # Increase by 50% | ||
9 | + | ||
10 | +# Choose the desired input and output devices | ||
11 | +input_device_index = 1 | ||
12 | +output_device_index = 1 | ||
13 | + | ||
14 | +# Open input stream | ||
15 | +input_stream = audio.open(input_device_index=input_device_index, format=pyaudio.paFloat32, | ||
16 | + channels=1, rate=44100, input=True, frames_per_buffer=1024) | ||
17 | + | ||
18 | +# Open output stream | ||
19 | +output_stream = audio.open(output_device_index=output_device_index, format=pyaudio.paFloat32, | ||
20 | + channels=2, rate=int(44100 * pitch_shift_factor), output=True) | ||
21 | + | ||
22 | +# Read input audio and apply pitch shift | ||
23 | +frames = [] | ||
24 | +while True: | ||
25 | + data = input_stream.read(1024) | ||
26 | + frames.append(data) | ||
27 | + | ||
28 | + # Adjust pitch by changing sample rate | ||
29 | + if len(frames) >= 1024: | ||
30 | + audio_data = b''.join(frames) | ||
31 | + audio_array = np.frombuffer(audio_data, dtype=np.float32) | ||
32 | + | ||
33 | + # Resample the audio array to change the pitch | ||
34 | + resampled_array = np.resize(audio_array, int(len(audio_array) / pitch_shift_factor)) | ||
35 | + | ||
36 | + # Convert the resampled array back to bytes | ||
37 | + resampled_data = resampled_array.astype(np.float32).tobytes() | ||
38 | + | ||
39 | + # Play the resampled audio | ||
40 | + output_stream.write(resampled_data) | ||
41 | + | ||
42 | + frames = [] | ||
43 | + | ||
44 | +# Stop and close the streams | ||
45 | +input_stream.stop_stream() | ||
46 | +input_stream.close() | ||
47 | +output_stream.stop_stream() | ||
48 | +output_stream.close() | ||
49 | + | ||
50 | +# Terminate PyAudio | ||
51 | +audio.terminate() |
sets.py
deleted
100644 → 0
1 | -import base64 | ||
2 | - | ||
3 | -task_list = [] | ||
4 | - | ||
5 | - | ||
6 | -def display_menu(): | ||
7 | - print("일정 관리자") | ||
8 | - print("1. 일정 추가") | ||
9 | - print("2. 일정 보기") | ||
10 | - print("3. 일정 완료 표시") | ||
11 | - print("4. 종료") | ||
12 | - | ||
13 | - | ||
14 | -def add_task(): | ||
15 | - title = input("일정 제목 입력: ") | ||
16 | - description = input("일정 설명 입력: ") | ||
17 | - status = "하는 중" | ||
18 | - task = { "title": title, "description": description, "status": status} | ||
19 | - task_list.append(task) | ||
20 | - print("일정이 추가되었습니다.") | ||
21 | - | ||
22 | - | ||
23 | -def view_tasks(): | ||
24 | - if not task_list: | ||
25 | - print("일정 목록이 비어 있습니다.") | ||
26 | - else: | ||
27 | - print() | ||
28 | - print("일정 목록:") | ||
29 | - print("----------------") | ||
30 | - for task in task_list: | ||
31 | - print(f"제목: {task['title']}") | ||
32 | - print(f"설명: {task['description']}") | ||
33 | - print(f"상태: {task['status']}") | ||
34 | - print("----------------") | ||
35 | - | ||
36 | - | ||
37 | -def mark_task_complete(): | ||
38 | - if not task_list: | ||
39 | - print("일정 목록이 비어 있습니다.") | ||
40 | - return | ||
41 | - | ||
42 | - title = input("완료로 표시할 일정의 제목 입력: ") | ||
43 | - for task in task_list: | ||
44 | - if task['title'] == title: | ||
45 | - task['status'] = "완료" | ||
46 | - print("일정이 완료로 표시되었습니다.") | ||
47 | - return | ||
48 | - | ||
49 | - print("식별자와 일치하는 일정을 찾을 수 없습니다.") | ||
50 | - | ||
51 | - | ||
52 | -while True: | ||
53 | - display_menu() | ||
54 | - choice = input("선택: ") | ||
55 | - | ||
56 | - if choice == "1": | ||
57 | - add_task() | ||
58 | - elif choice == "2": | ||
59 | - view_tasks() | ||
60 | - elif choice == "3": | ||
61 | - mark_task_complete() | ||
62 | - elif choice == "4": | ||
63 | - print("프로그램을 종료합니다.") | ||
64 | - break | ||
65 | - else: | ||
66 | - print("올바른 선택지를 입력하세요.") | ||
67 | - print() | ||
68 | - |
No preview for this file type
No preview for this file type
No preview for this file type
sounds/ping.mp3
0 → 100644
No preview for this file type
sounds/s1.mp3
0 → 100644
No preview for this file type
... | @@ -2,6 +2,7 @@ import sys | ... | @@ -2,6 +2,7 @@ import sys |
2 | import numpy as np | 2 | import numpy as np |
3 | import pyaudio | 3 | import pyaudio |
4 | import librosa | 4 | import librosa |
5 | +import scipy.signal as signal | ||
5 | 6 | ||
6 | RECORD_SECONDS = 5 | 7 | RECORD_SECONDS = 5 |
7 | CHUNK = 1024 | 8 | CHUNK = 1024 |
... | @@ -10,11 +11,14 @@ DELAY = 0.1 # Delay time in seconds | ... | @@ -10,11 +11,14 @@ DELAY = 0.1 # Delay time in seconds |
10 | GAIN = 1 # Echo gain (0 to 1) | 11 | GAIN = 1 # Echo gain (0 to 1) |
11 | MAX_FREQ = 3000 | 12 | MAX_FREQ = 3000 |
12 | 13 | ||
14 | +input_device_index = 1 | ||
15 | +output_device_index = 4 | ||
16 | + | ||
13 | # Create buffer for delayed audio data | 17 | # Create buffer for delayed audio data |
14 | buffer_size = int(RATE * DELAY) | 18 | buffer_size = int(RATE * DELAY) |
15 | buffer = np.zeros(buffer_size, dtype=np.int16) | 19 | buffer = np.zeros(buffer_size, dtype=np.int16) |
16 | 20 | ||
17 | -def add_echo(in_data, frame_count, time_info, status_flags): | 21 | +def do_process(in_data, frame_count, time_info, status_flags): |
18 | global buffer | 22 | global buffer |
19 | data = np.frombuffer(in_data, dtype=np.int16) | 23 | data = np.frombuffer(in_data, dtype=np.int16) |
20 | 24 | ||
... | @@ -22,7 +26,7 @@ def add_echo(in_data, frame_count, time_info, status_flags): | ... | @@ -22,7 +26,7 @@ def add_echo(in_data, frame_count, time_info, status_flags): |
22 | data_float = data.astype(np.float32) | 26 | data_float = data.astype(np.float32) |
23 | 27 | ||
24 | # Compute the power spectrogram of the data | 28 | # Compute the power spectrogram of the data |
25 | - S = librosa.stft(data_float, n_fft=2048, hop_length=512) | 29 | + S = librosa.stft(data_float, n_fft=256, hop_length=512) |
26 | S_power = np.abs(S)**2 | 30 | S_power = np.abs(S)**2 |
27 | 31 | ||
28 | # Convert power spectrogram to dB scale | 32 | # Convert power spectrogram to dB scale |
... | @@ -47,7 +51,7 @@ def add_echo(in_data, frame_count, time_info, status_flags): | ... | @@ -47,7 +51,7 @@ def add_echo(in_data, frame_count, time_info, status_flags): |
47 | freqs = np.fft.fftfreq(len(psd_data), d=1/RATE) | 51 | freqs = np.fft.fftfreq(len(psd_data), d=1/RATE) |
48 | 52 | ||
49 | # Compute the power spectrogram on the mel scale | 53 | # Compute the power spectrogram on the mel scale |
50 | - S = librosa.feature.melspectrogram(y=data, sr=RATE, n_fft=2048, hop_length=1024) | 54 | + S = librosa.feature.melspectrogram(y=data, sr=RATE, n_fft=256, hop_length=1024, n_mels=64) |
51 | 55 | ||
52 | # Find the frequency bin with the maximum energy in each frame | 56 | # Find the frequency bin with the maximum energy in each frame |
53 | max_bin = np.argmax(S, axis=0) | 57 | max_bin = np.argmax(S, axis=0) |
... | @@ -60,14 +64,47 @@ def add_echo(in_data, frame_count, time_info, status_flags): | ... | @@ -60,14 +64,47 @@ def add_echo(in_data, frame_count, time_info, status_flags): |
60 | 64 | ||
61 | return dominant_freq | 65 | return dominant_freq |
62 | 66 | ||
63 | - freq = get_dominant_freq(data) | 67 | + def add_echo(gain): |
64 | - avg_db, max_db = get_max_average_db(data) | 68 | + global buffer |
65 | - print(int(freq), int(avg_db), int(max_db)) | 69 | + buffer = np.roll(buffer, len(data)) |
66 | - temp_gain = freq/MAX_FREQ | 70 | + buffer[-len(data):] = data |
67 | - output = data + freq/2500 * buffer[:len(data)] | 71 | + return data + gain * buffer[:len(data)] |
68 | - buffer = np.roll(buffer, len(data)) | 72 | + |
69 | - buffer[-len(data):] = data | 73 | + def shift_pitch(pitch_shift_factor): |
70 | - return (output.astype(np.int16).tostring(), pyaudio.paContinue) | 74 | + audio_array = data |
75 | + # Resample the audio array to change the pitch | ||
76 | + resampled_array = np.resize(audio_array, int(len(audio_array) / pitch_shift_factor)) | ||
77 | + | ||
78 | + return resampled_array | ||
79 | + | ||
80 | + def high_filter(param): | ||
81 | + audio_data = data | ||
82 | + # Define the filter parameters | ||
83 | + cutoff_freq = param * MAX_FREQ # Frequency cutoff for the low-pass filter (in Hz) | ||
84 | + nyquist_freq = 0.5 * RATE # Nyquist frequency (half of the sampling rate) | ||
85 | + normalized_cutoff = cutoff_freq / nyquist_freq # Normalized cutoff frequency | ||
86 | + | ||
87 | + # Design the low-pass filter | ||
88 | + b, a = signal.butter(4, normalized_cutoff, btype='low', analog=False, output='ba') | ||
89 | + | ||
90 | + # Apply the low-pass filter to the audio data | ||
91 | + filtered_audio = signal.lfilter(b, a, audio_data) | ||
92 | + | ||
93 | + return filtered_audio | ||
94 | + | ||
95 | + try: | ||
96 | + freq = get_dominant_freq(data) | ||
97 | + # avg_db, max_db = get_max_average_db(data) | ||
98 | + | ||
99 | + # temp_gain = freq/MAX_FREQ | ||
100 | + # output = add_echo(temp_gain) | ||
101 | + output = shift_pitch(0.5 + freq/MAX_FREQ) | ||
102 | + # output = high_filter(0.5) | ||
103 | + # print(int(freq), int(avg_db), int(max_db)) | ||
104 | + return (output.astype(np.int16).tobytes(), pyaudio.paContinue) | ||
105 | + except: | ||
106 | + print("exception occured") | ||
107 | + return data | ||
71 | 108 | ||
72 | 109 | ||
73 | p = pyaudio.PyAudio() | 110 | p = pyaudio.PyAudio() |
... | @@ -75,9 +112,11 @@ stream = p.open(format=p.get_format_from_width(2), | ... | @@ -75,9 +112,11 @@ stream = p.open(format=p.get_format_from_width(2), |
75 | channels=1 if sys.platform == 'darwin' else 2, | 112 | channels=1 if sys.platform == 'darwin' else 2, |
76 | rate=RATE, | 113 | rate=RATE, |
77 | input=True, | 114 | input=True, |
115 | + input_device_index=input_device_index, | ||
116 | + output_device_index=output_device_index, | ||
78 | output=True, | 117 | output=True, |
79 | frames_per_buffer=CHUNK, | 118 | frames_per_buffer=CHUNK, |
80 | - stream_callback=add_echo | 119 | + stream_callback=do_process |
81 | ) | 120 | ) |
82 | 121 | ||
83 | print('* recording') | 122 | print('* recording') | ... | ... |
... | @@ -6,4 +6,6 @@ | ... | @@ -6,4 +6,6 @@ |
6 | 6 | ||
7 | 1. 실제 소리변형으로 뭔가 만들기 | 7 | 1. 실제 소리변형으로 뭔가 만들기 |
8 | - 실제 소리가 들릴거냐 말거냐 | 8 | - 실제 소리가 들릴거냐 말거냐 |
9 | -2. identification만 하고, 다른 소리 재생도 할 수 있음. | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
9 | +2. identification만 하고, 다른 소리 재생도 할 수 있음. | ||
10 | + | ||
11 | +- 소리 identification을 진행? | ... | ... |
-
Please register or login to post a comment