add audio and record widget

This commit is contained in:
yumoqing 2022-07-09 22:06:08 +08:00
parent 7d7f4ac472
commit a922670413
4 changed files with 97 additions and 41 deletions

View File

@ -16,6 +16,7 @@ class Audio(AppLogger, pyaudio.PyAudio):
self.chunk = 1024 self.chunk = 1024
self.devices = [ self.get_device_info_by_index(i) \ self.devices = [ self.get_device_info_by_index(i) \
for i in range(self.get_device_count()) ] for i in range(self.get_device_count()) ]
self.recording = False
def get_input_device(self): def get_input_device(self):
return [ d for d in self.devices if d.maxInputChannels > 0 ] return [ d for d in self.devices if d.maxInputChannels > 0 ]
@ -27,24 +28,16 @@ class Audio(AppLogger, pyaudio.PyAudio):
x = tempfile.mkstemp(suffix='.wav') x = tempfile.mkstemp(suffix='.wav')
os.close(x[0]) os.close(x[0])
self.temp_filename = x[1] self.temp_filename = x[1]
return self.temp_filename
def record_cb(self, in_data, frame_count, time_info, status): def record_cb(self, in_data, frame_count, time_info, status):
bdata = pickle.dumps(in_data)
self.info('frame_count=%s, time_info=%s, status=%s, bytes count=%s', \
frame_count, time_info, status, len(bdata))
self.rec_frames += frame_count
self.current_ts = time.time()
self.wavfile.writeframesraw(in_data) self.wavfile.writeframesraw(in_data)
if self.running: if self.recording:
return (None, pyaudio.paContinue) return (None, pyaudio.paContinue)
return (None, pyaudio.paComplete) return (None, pyaudio.paComplete)
def replay_cb(self, in_data, frame_count, time_info, status): def replay_cb(self, in_data, frame_count, time_info, status):
data = self.wavfile.readframes(frame_count) data = self.wavfile.readframes(frame_count)
bdata = pickle.dumps(data)
self.info('frame_count=%s, data length in bytes=%s', \
frame_count, len(bdata))
if not data: if not data:
return (None, pyaudio.paComplete) return (None, pyaudio.paComplete)
@ -57,35 +50,42 @@ class Audio(AppLogger, pyaudio.PyAudio):
print(x) print(x)
return dev_cnt - 1 return dev_cnt - 1
def record(self, save_file=None, stop_cond_func=None): def start_record(self,
filename = save_file savefile=None,
if filename is None:
self.tmpfile()
filename = self.temp_filename
self.wavfile = wave.open(filename, 'wb')
self.wavfile.setnchannels(2)
self.wavfile.setsampwidth(2)
self.wavfile.setframerate(44100.00)
self.stream = self.open(format=pyaudio.paInt16,
channels=2, channels=2,
rate=44100, rate=44100
):
if savefile is None:
savefile = self.tmpfile()
self.save_file = savefile
self.wavfile = wave.open(self.save_file, 'wb')
self.wavfile.setnchannels(channels)
self.wavfile.setsampwidth(2)
self.wavfile.setframerate(rate)
self.stream = self.open(format=pyaudio.paInt16,
channels=channels,
rate=rate,
input=True, input=True,
frames_per_buffer=self.chunk, frames_per_buffer=self.chunk,
stream_callback=self.record_cb) stream_callback=self.record_cb)
self.stream.start_stream() self.stream.start_stream()
self.running = True self.recording = True
self.rec_frames = 0
self.start_ts = self.current_ts = time.time() def stop_record(self):
while self.stream.is_active(): if self.recording:
if stop_cond_func and stop_cond_func(): self.stream.stop_stream()
self.running = False self.stream.close()
time.sleep(0.05) self.wavfile.close()
self.stream.stop_stream()
self.stream.close() def record(self, stop_cb,
self.wavfile.close() savefile=None,
if save_file is None: channels=2,
self.replay() rate=44100,
):
self.start_record(savefile=savefile, channels=channels,rate=rate)
while not stop_cb():
time.sleep(0.1)
self.stop_record()
def replay(self, play_file=None): def replay(self, play_file=None):
idx = self.get_output_index() idx = self.get_output_index()
@ -118,9 +118,12 @@ class Audio(AppLogger, pyaudio.PyAudio):
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
t_begin = time.time()
def stop_func(audio): def stop_func(audio):
if audio.current_ts - audio.start_ts >= 10: t = time.time()
audio.running = False if t - t_begin >= 10:
return True
return False
create_logger('audio', levelname='debug') create_logger('audio', levelname='debug')
a = Audio() a = Audio()
@ -135,4 +138,4 @@ if __name__ == '__main__':
if len(sys.argv) >= 2: if len(sys.argv) >= 2:
sf = sys.argv[1] sf = sys.argv[1]
f = partial(stop_func, a) f = partial(stop_func, a)
a.record(sf, stop_cond_func=f) a.record(f, savefile=sf)

View File

@ -3,14 +3,14 @@ import tempfile
import pyaudio import pyaudio
import wave import wave
from kivy.event import EventDispatcher from kivy.event import EventDispatcher
from kivy.properties import NumericProperty from kivy.properties import NumericProperty, StringProperty, ObjectProperty
from kivyblocks.baseWidget import HBox from kivyblocks.baseWidget import HBox
from kviycv.micphone import Micphone from kivycv.micphone import Micphone
class AudioRecorder(EventDispatcher): class AudioRecorder(EventDispatcher):
fs = NumericProperty(None) fs = NumericProperty(None)
filename = StringProperty(None) filename = StringProperty(None)
voice_src = OjbectProperty(None) voice_src = ObjectProperty(None)
def __init__(self, **kw): def __init__(self, **kw):
super(AudioRecorder, self).__init__(**kw) super(AudioRecorder, self).__init__(**kw)
self.saving = False self.saving = False

View File

@ -6,7 +6,7 @@ from kivy.uix.camera import Camera
from kivy.properties import NumericProperty from kivy.properties import NumericProperty
from kivy.event import EventDispatcher from kivy.event import EventDispatcher
from .android_rotation import * from kivyblocks.android_rotation import *
if kivy.platform in [ 'win', 'linux', 'macosx' ]: if kivy.platform in [ 'win', 'linux', 'macosx' ]:
from PIL import ImageGrab from PIL import ImageGrab

53
kivycv/recorder.py Normal file
View File

@ -0,0 +1,53 @@
import pyaudio
from kivy.uix.label import Label
from kivy.properties import NumericProperty
from kivyblocks.baseWidget import HBox, VBox
import os
import sys
import time
try:
from .audio import Audio
except:
from audio import Audio
class Recorder(VBox):
rate = NumericProperty(44100)
channel = NumericProperty(2)
def __init__(self, **kw):
super().__init__(**kw)
self.audio = Audio()
self.register_event_type('on_recorded')
def on_recorded(self, record_file):
print('on_recorded:', record_file)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.audio.start_record(channels=self.channel,
rate=self.rate)
return False
return super().on_touch_down(touch)
def on_touch_up(self, touch):
if self.audio.recording:
self.audio.stop_record()
self.dispatch('on_recorded', self.audio.save_file)
return super().on_touch_up(touch)
if __name__ == '__main__':
from kivy.app import App
class TestApp(App):
def build(self):
x = Recorder()
self.recorder = x
x.bind(on_recorded=self.play_audio)
return x
def play_audio(self, o, f):
print('play file', f)
self.recorder.audio.replay(f)
print('play finished')
# os.remove(f)
TestApp().run()