2024.10.20 - [데이터&AI/LLM] - [realtime GPT를 쓰기위한 사전학습]pyaudio이해하기① (마이크 음성을 데이터로 전환!!!)
지난 포스팅에 이어 pyaudio 에 대하여 더 알아보겠습니다!!
오늘은!!
지난번 소리를 데이터로 전환하는것과 반대로!!
데이터를 소리로 전환해보겠습니다!!
OpenAI로부터 응답이온 데이터를 소리로 만들어서 스피커가 켤수 있어야겠찌요!?
묻고 따지지 않고 아래 코드를 실행해봅다!!
※ 주의!! 전자음이 나오니 스피커 소리를 작게하고 틀어주세요!!
import numpy as np
import pyaudio
# PyAudio 설정
FORMAT = pyaudio.paInt16 # 16비트 오디오
CHANNELS = 1 # 모노 채널
RATE = 44100 # 샘플링 레이트 (44.1kHz)
DURATION = 2 # 삐 소리의 지속 시간 (초)
FREQUENCY = 1000 # 삐 소리의 주파수 (1000Hz)
# PyAudio 초기화
p = pyaudio.PyAudio()
# 사인파 생성 함수 (삐 소리 데이터 생성)
def generate_beep(frequency, duration, rate):
t = np.linspace(0, duration, int(rate * duration), False) # 시간 배열 생성
# 사인파 생성 (16비트 정수형)
beep_data = np.sin(2 * np.pi * frequency * t) * 32767 # 16비트로 변환
return beep_data.astype(np.int16).tobytes() # 바이트 형태로 변환하여 반환
# 스피커로 소리 출력하는 콜백 함수
def _spkr_callback(in_data, frame_count, time_info, status):
# 스피커로 출력할 오디오 데이터
audio_chunk = beep_data[:frame_count * 2] # 필요한 만큼 청크로 자름
return (audio_chunk, pyaudio.paContinue)
# 삐 소리 데이터 생성 (주파수 1000Hz, 지속 시간 2초)
beep_data = generate_beep(FREQUENCY, DURATION, RATE)
# PyAudio 출력 스트림 설정 (스피커로 출력)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
output=True, # 스피커 출력
frames_per_buffer=1024,
stream_callback=_spkr_callback)
# 스트림 시작
stream.start_stream()
# 삐 소리 출력하는 동안 대기
print("삐 소리가 스피커로 출력됩니다.")
while stream.is_active():
pass
# 스트림 종료
stream.stop_stream()
stream.close()
p.terminate()
실행해보니 어떤가요!?
삐~~~~~~ 하는 소리가 나지요!?
그 원리를 파악해봅시다~!
1. 소리데이터 만들기
> 실제로는 OpenAI의 socket에서 답변온 데이터로 재생하겠지만,
> 지금은 데이터를 만들어서 테스트해야합니다! 이에!
> 소리데이터 생성 부분은 아래와 같습니다!
> 쉽게 생각하면 사인파형의 데이터를 생성하는것이지요~~
# 사인파 생성 함수 (삐 소리 데이터 생성)
def generate_beep(frequency, duration, rate):
t = np.linspace(0, duration, int(rate * duration), False) # 시간 배열 생성
# 사인파 생성 (16비트 정수형)
beep_data = np.sin(2 * np.pi * frequency * t) * 32767 # 16비트로 변환
return beep_data.astype(np.int16).tobytes() # 바이트 형태로 변환하여 반환
간단히 numpy array를 확인해보면!
위와 같이 숫자의 모음? 이라고 생각하며됩니다!!
2. call_back함수 이해!
지난 포스팅에서 indata로 반영되었던 call back 함수 기억나시나요~!!?
이번에도 마찬가지인데요!! "_spkr_callback" 라는 함수를 만들고,
pyaudio 객채를 만들때 아래와 같이 callback 함수로 선언해줍니다!
# PyAudio 초기화
p = pyaudio.PyAudio()
# PyAudio 출력 스트림 설정 (스피커로 출력)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
output=True, # 스피커 출력
frames_per_buffer=1024,
stream_callback=_spkr_callback)
그리고!! "_spkr_callback" 함수를 살펴보면!?
# 스피커로 소리 출력하는 콜백 함수
def _spkr_callback(in_data, frame_count, time_info, status):
# 스피커로 출력할 오디오 데이터
audio_chunk = beep_data[:frame_count * 2] # 필요한 만큼 청크로 자름
return (audio_chunk, pyaudio.paContinue)
위와 같이!! 여기서도 in_data로 데이터가 들어오고,
(이번 테스트의 경우 외부에서 오는 데이터가 없기에 in_data는 사용되지 않지만요@!)
이후 여기서는 위의 generate_beep 로 생성된 beep_data를 audio_chunk로 만들고!!
audio_chunk는 PyAudio에 의해 스피커로 출력되도록 반환됩니다.
콜백 함수는 매번 호출될 때마다 이 데이터를 PyAudio에 전달하며, PyAudio는 그 데이터를 스피커로 출력합니다.
이해가 되셨나요!?
이제는 마지막으로!! 내 목소리를 데이터로 저장하고, 그 데이터를 불러와서 스피커로 실행해보는 마지막 테스트를 진행해 보겠습니다!
3. 마지막 복습 : 목소리 > 데이터 > 소리
아래와 같은 순서로 진행됩니다!!
1. record_voice : 내 목소리가 녹음되고!! numpy 배열이 저장
2. play_voice : numpy 로 저장된 데이터를 불러와서 소리로 실행!!
아래 코드를 봅시다!!
import pyaudio
import numpy as np
# PyAudio 설정
FORMAT = pyaudio.paInt16 # 16비트 오디오
CHANNELS = 1 # 모노 채널
RATE = 44100 # 샘플링 레이트 (44.1kHz)
CHUNK = 1024 # 버퍼 크기
RECORD_SECONDS = 5 # 녹음 시간 (5초)
AUDIO_FILE = "audio_data.txt" # 저장할 텍스트 파일 이름
# PyAudio 초기화
p = pyaudio.PyAudio()
# 1. 마이크로부터 오디오를 입력받아 NumPy 배열에 저장하고, 텍스트 파일로 저장하는 함수
def record_voice():
print("녹음을 시작합니다. 마이크에 대고 말하세요...")
# 입력 스트림 설정 (마이크에서 입력받음)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
frames = [] # 오디오 데이터를 저장할 리스트
# CHUNK 크기만큼 데이터를 읽고 저장 (RECORD_SECONDS 동안 반복)
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(np.frombuffer(data, dtype=np.int16)) # 데이터를 NumPy 배열로 변환
print("녹음이 끝났습니다.")
# 스트림 종료
stream.stop_stream()
stream.close()
# NumPy 배열로 변환
audio_data = np.hstack(frames) # 모든 데이터를 하나의 NumPy 배열로 합침
# NumPy 배열을 텍스트 파일로 저장
np.savetxt(AUDIO_FILE, audio_data, fmt='%d') # 정수 형태로 저장
print(f"오디오 데이터가 {AUDIO_FILE}에 저장되었습니다.")
# 2. 텍스트 파일에서 NumPy 배열을 불러와 스피커로 재생하는 함수
def play_voice():
print(f"{AUDIO_FILE}에서 오디오 데이터를 불러옵니다...")
# 텍스트 파일에서 NumPy 배열 불러오기
audio_data = np.loadtxt(AUDIO_FILE, dtype=np.int16)
print("저장된 목소리를 재생합니다...")
# 출력 스트림 설정 (스피커로 출력)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
output=True)
# NumPy 배열 데이터를 CHUNK 크기로 나누어 재생
start = 0
while start < len(audio_data):
end = min(start + CHUNK, len(audio_data))
stream.write(audio_data[start:end].tobytes()) # 데이터를 바이트로 변환 후 출력
start = end
# 스트림 종료
stream.stop_stream()
stream.close()
# PyAudio 종료
def terminate_pyaudio():
p.terminate()
# 3. 전체 실행 순서
if __name__ == "__main__":
# 목소리 녹음 (NumPy 배열로 저장하고 텍스트 파일로 기록)
record_voice()
# 녹음된 데이터를 텍스트 파일에서 불러와 재생
play_voice()
# PyAudio 종료
terminate_pyaudio()
코드를 실행해보면!!
녹음된 목소리가 정말 잘 실행되구요!!
내 디렉토리에는 audio_data.txt라는 텍스트 파일로!!
220127 개의 배열 데이터가 잘 저장됨을 확인할 수 있었습니다!
지금까지!! pyaudio를 활용하여!
소리를 데이터로! 그리규 데이터를 소리로 바꾸는 방법에 대하여 알아보았습니다!!
'데이터&AI > 기타개발' 카테고리의 다른 글
[realtime GPT를 쓰기위한 사전학습] socket통신의 이해 (python에서의 TCP 통신!) (0) | 2024.10.24 |
---|---|
[realtime GPT를 쓰기위한 사전학습] queue 의 이해 (python. 줄을 서시오!! FIFO) (2) | 2024.10.18 |
[realtime GPT를 쓰기위한 사전학습] threading의 이해 (python의 멀티태스킹!) (1) | 2024.10.17 |
Python으로 주말 or 공휴일 체크하는 로직 만들기 (with 공공 API) (0) | 2024.10.14 |
[Deepvoice] 내 목소리를 학습, 파일을 생성해보자!! (클릭만하면됨) (2) | 2024.09.05 |
댓글