diff --git a/kivyblocks/audiorecorder.py b/kivyblocks/audiorecorder.py new file mode 100644 index 0000000..24581a2 --- /dev/null +++ b/kivyblocks/audiorecorder.py @@ -0,0 +1,44 @@ + +import tempfile +import pyaudio +import wave +from kivy.event import EventDispatcher +from kivy.properties import NumericProperty +from kivyblocks.baseWidget import HBox +from kviyblocks.micphone import Micphone + +class AudioRecorder(EventDispatcher): + fs = NumericProperty(None) + filename = StringProperty(None) + voice_src = OjbectProperty(None) + def __init__(self, **kw): + super(AudioRecorder, self).__init__(**kw) + self.saving = False + if not self.filename: + self.mk_temp_file() + + def mk_temp_file(self): + self.filename = tempfile.mktemp(suffix='.wav') + + def on_filename(self, *args): + self.wf = wave.open(self.filename, 'wb') + + def on_voice_src(self, *args): + audio_profile = self.voice_src.audio_profile() + self.wf.setnchannels(audio_profile['channels']) + self.wf.setsamplewidth(audio_profile['sample_size']) + self.wf.setframerate(audio_profiel['sample_rate']) + self.voice_src.bind(on_fps=self.write) + + def write(self, o, d): + if self.saving: + self.wf.write(''.join(d)) + + def start(self): + if not self.voice_src.recording: + self.voice_src.start() + self.saving = True + + def stop(self): + self.saving = False + wf.close() diff --git a/kivyblocks/blocks.py b/kivyblocks/blocks.py index d9c6fb8..c0906da 100755 --- a/kivyblocks/blocks.py +++ b/kivyblocks/blocks.py @@ -572,8 +572,10 @@ class Blocks(EventDispatcher): } """ def doit(desc): + if isinstance(desc,DictObject): + desc = desc.to_dict() if not isinstance(desc,dict): - Logger.info('Block: desc must be a dict object', + Logger.info('Block: desc(%s) must be a dict object(%s)', desc,type(desc)) return None diff --git a/kivyblocks/markdown.py b/kivyblocks/markdown.py index d0e5cf1..493914d 100644 --- a/kivyblocks/markdown.py +++ b/kivyblocks/markdown.py @@ -31,6 +31,14 @@ description file format print('size changed') for c in self._inner.children: c.width = self.width + if isinstance(c, Factory.Text): + _, h = c.get_wraped_size() + clen = CSize(1) + if not h or h < clen: + c.height = clen + else: + c.height = h + self._inner.do_layout() def load_text(self, *args): print('source fired, hahaha', *args) @@ -51,14 +59,13 @@ description file format l = ''.join([i for i in l if i != '\r']) self.parse_line(l) - def parse_title(self,txt, level): + def parse_title(self, txt, level): w = Factory.Blocks().widgetBuild({ "widgettype":f"Title{level}", "options":{ "text":txt, "size_hint_x":None, "width":self.width, - "minimum_width":self.width, "size_hint_y":None, "markup":True, "wrap":True, @@ -66,12 +73,14 @@ description file format "valign":"middle" } }) - _,h = w.get_wraped_size() + if not w: + return + w1,h1 = w.get_wraped_size() clen = CSize(1) - if h is None or h < clen: - h = clen - w.height = h - print(w,h,w.height) + if h1 is None or h1 < clen: + h1 = clen + w.height = h1 + print(w, w1, h1, w.height) w.bind(on_ref_press=self.open_new_md) self.add_widget(w) @@ -102,12 +111,13 @@ description file format "wrap":True, "size_hint_x":None, "width":self.width, - "minimum_width":self.width, "markup":True, "valign":"middle", "halign":"left" } }) + if not w: + return _,h = w.get_wraped_size() clen = CSize(1) if h is None or h < clen: diff --git a/kivyblocks/micphone.py b/kivyblocks/micphone.py index c54edd0..9bce441 100644 --- a/kivyblocks/micphone.py +++ b/kivyblocks/micphone.py @@ -6,13 +6,14 @@ import wave CHUNK = 1024 CHANNELS = 2 FORMAT = pyaudio.paInt16 -rate = 48000 +samplerate = 48000 -class Micphone: +class Micphone(EventDispatcher): channels = NumericProperty(2) - rate = NumericProperty(48000) + samplerate = NumericProperty(48000) fps = NumericProperty(1/60) def __init__(self, **kw): + super(Micphone, self).__init__(**kw) self.chunk = CHUNK self.format = pyaudio.Int16 self.chunk_buffer = [] @@ -21,21 +22,29 @@ class Micphone: self._audio = puaudio.PyAudio() self._mic = p.open(format=self.format, channels=self.channels, - rate=self.rate, + rate=self.samplerate, input=True, frames_per_buffer=self.chunk) self.sampe_size = self.audio.get_sample_size(self.format) self.register_event_type('on_fps') + self.register_event_type('on_start') + self.register_event_type('on_end') self.fps_task = None def on_fps(self, d): print('on_fps fired') + def on_start(self): + print('on_start fired') + + def on_end(self): + print('on_end fired') + def audio_profile(self): return { 'channels':self.channels, 'sample_size':self.sample_size, - 'rate':self.rate + 'sample_rate':self.samplerate } def get_frames(self, *args): @@ -52,6 +61,7 @@ class Micphone: def start(self, *args): self.recording = True Background(self._record) + self.dispatch('on_start') self.fps_task = Clock.schedule_interval(self.get_frames, self.fps) def _record(self): @@ -65,6 +75,7 @@ class Micphone: def stop(self, *args): self.recording = False self.fps_task.cancel() + self.dispatch('on_end') def close(self): self._mic.stop_stream() diff --git a/kivyblocks/osc_server.py b/kivyblocks/osc_server.py deleted file mode 100644 index 80cf0e4..0000000 --- a/kivyblocks/osc_server.py +++ /dev/null @@ -1,67 +0,0 @@ -import json -from functools import partial -from kivy.event import EventDispatcher -from kivy.clock import Clock -from oscpy.server import OSCThreadServer -from oscpy.client import send_message, OSCClient - -class OSCServer(EventDispatcher): - def __init__(self,addr='0.0.0.0', - port=60405, - apis=[]): - self.port = port - self.addr = addr - self.clients = [] - self.osc_server = OSCThreadServer() - sock = self.osc_server.listen(self.addr,port=self.port,default=True) - EventDispatcher.__init__(self) - apis.append('broadcast') - for api in apis: - event_name = 'on_%s' % api - f = partial(self.handle, api) - setattr(self, event_name, f) - self.register_event_type(event_name) - api_f = partial(self.apihandle,api) - bstr = '/%s' % api - bstr.encode('utf-8') - self.osc_server.bind(bstr, api_f, sock) - - def info(self): - ip,port = self.osc_server.getaddress() - return { - "ip":ip, - "port":port - } - - def stop(self): - self.osc_server.stop() - - def handle(self,api,o,*args): - print(api, *args) - - def apihandle(self, api, *args): - print('OSCServer():apihandle():api=', api, 'args=',args) - data = args[0].decode('utf-8') - data = json.loads(data) - sock, ip_address, response_port = self.osc_server.get_sender() - self.dispatch('on_%s' % api, api, data) - if api == 'broadcast': - return - if not address in self.clients: - self.clients.append([ip_address, response_port]) - - def send_message(self,api, data, addr, port): - data = json.dumps(data) - data = data.encode('utf-8') - bstr = '/%s' % api - bstr = bstr.encode('utf-8') - print('api=', bstr, - 'data=', data, - 'addr=', addr, - 'port=',port) - send_message(bstr, [data], addr, port) - - def broadcast(self, data): - for address in self.clients: - self.osc_server.send_message('broadcast', data, *address) - diff --git a/kivyblocks/ready.py b/kivyblocks/ready.py index 54ded91..2954850 100644 --- a/kivyblocks/ready.py +++ b/kivyblocks/ready.py @@ -1,4 +1,3 @@ -from kivy.event import EventDispatcher from kivy.core.window import Window from kivy.utils import platform from kivy.app import App diff --git a/kivyblocks/tree.py b/kivyblocks/tree.py index 29589fa..21fe66a 100644 --- a/kivyblocks/tree.py +++ b/kivyblocks/tree.py @@ -16,6 +16,7 @@ from .baseWidget import PressableLabel from .color_definitions import getColors from .bgcolorbehavior import BGColorBehavior from .utils import alert,absurl +from .threadcall import HttpClient class EmptyBox(Label): def __init__(self,size_cnt=1): @@ -323,7 +324,7 @@ class Tree(BGColorBehavior, ScrollWidget): self.NodeKlass = klass def getUrlData(self,callback,kv=None): - hc = App.get_running_app().hc + hc = HttpClient() params = self.options.get('params',{}).copy() if not kv is None: for k,v in kv.items():