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.devices = [ self.get_device_info_by_index(i) \
for i in range(self.get_device_count()) ]
self.recording = False
def get_input_device(self):
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')
os.close(x[0])
self.temp_filename = x[1]
return self.temp_filename
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)
if self.running:
if self.recording:
return (None, pyaudio.paContinue)
return (None, pyaudio.paComplete)
def replay_cb(self, in_data, frame_count, time_info, status):
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:
return (None, pyaudio.paComplete)
@ -57,35 +50,42 @@ class Audio(AppLogger, pyaudio.PyAudio):
print(x)
return dev_cnt - 1
def record(self, save_file=None, stop_cond_func=None):
filename = save_file
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,
def start_record(self,
savefile=None,
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,
frames_per_buffer=self.chunk,
stream_callback=self.record_cb)
self.stream.start_stream()
self.running = True
self.rec_frames = 0
self.start_ts = self.current_ts = time.time()
while self.stream.is_active():
if stop_cond_func and stop_cond_func():
self.running = False
time.sleep(0.05)
self.stream.stop_stream()
self.stream.close()
self.wavfile.close()
if save_file is None:
self.replay()
self.recording = True
def stop_record(self):
if self.recording:
self.stream.stop_stream()
self.stream.close()
self.wavfile.close()
def record(self, stop_cb,
savefile=None,
channels=2,
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):
idx = self.get_output_index()
@ -118,9 +118,12 @@ class Audio(AppLogger, pyaudio.PyAudio):
if __name__ == '__main__':
import sys
t_begin = time.time()
def stop_func(audio):
if audio.current_ts - audio.start_ts >= 10:
audio.running = False
t = time.time()
if t - t_begin >= 10:
return True
return False
create_logger('audio', levelname='debug')
a = Audio()
@ -135,4 +138,4 @@ if __name__ == '__main__':
if len(sys.argv) >= 2:
sf = sys.argv[1]
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 wave
from kivy.event import EventDispatcher
from kivy.properties import NumericProperty
from kivy.properties import NumericProperty, StringProperty, ObjectProperty
from kivyblocks.baseWidget import HBox
from kviycv.micphone import Micphone
from kivycv.micphone import Micphone
class AudioRecorder(EventDispatcher):
fs = NumericProperty(None)
filename = StringProperty(None)
voice_src = OjbectProperty(None)
voice_src = ObjectProperty(None)
def __init__(self, **kw):
super(AudioRecorder, self).__init__(**kw)
self.saving = False

View File

@ -6,7 +6,7 @@ from kivy.uix.camera import Camera
from kivy.properties import NumericProperty
from kivy.event import EventDispatcher
from .android_rotation import *
from kivyblocks.android_rotation import *
if kivy.platform in [ 'win', 'linux', 'macosx' ]:
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()