多亏@JFSebastian 和他的代码,我才知道:
最好使用截止日期作为时间参考,而不是在每个循环中创建新的参考使用截止日期可以使time.sleep的不精确度“摊销”,在所需的比特率附近振荡一点,但会得出正确的(并且要更稳定)的平均值。您只需要使用一次time.time(),这意味着更少的计算误差。结果,我得到了恒定的32000 B / s振荡到31999,很少能振荡到31745。现在我可以听到音乐了,没有任何滞后或抖动!
我尝试仅使用%运算符来使用@JFSebastian强制性操作来使其余部分hibernate,但KB /s异常地波动,因此我决定保留截止日期实现,因为通过增加浮点值会造成不精确性。但是,总体结果足以满足我的需求。谢谢大家。
最终密码def read(self): self.deadline += 0.020 delay = self.deadline - time.perf_counter() if delay > 0:time.sleep(delay) return self._read()解决方法 语境
我在计算机(播放器)上使用Windows 7,而在大学计算机(流媒体)上使用linux(debian),我使用ssh对其进行控制。我试图通过读取波形文件来模拟麦克风的恒定字节速率,就像有人在说话一样。问题在于字节速率低于目标。
选择32KB / s的速率和0.020秒的捕获时间。我使用time.sleep实现了模拟麦克风,以每0.020秒产生每个数据块。但是获得的速率约为27KB / s,而不是32KB / s
问题我决定通过阅读此问题,使用一些想法来测试linux机器上time.sleep的精确度。
我做了2种测试。1)繁忙的睡眠2)正常的睡眠
平均而言,从我得到的样本中可以看出,Linux机器的睡眠分辨率为4ms。在Windows上时,其小于/等于1毫秒。
问题有什么可能会限制linux机器上的睡眠分辨率? (在Linux上)为什么繁忙的睡眠与time.sleep具有相同的分辨率?如何通过读取波形文件成功模拟麦克风?码import timedef busy_sleep(t): s=time.time() while time.time() - s < t:pass e=time.time() return e-sdef normal_sleep(t): s=time.time() time.sleep(t) e=time.time() return e-sdef test(fun): f = lambda x: sum(fun(x) for d in range(10))/10 print('0.100:{}'.format(f(0.100))) print('0.050:{}'.format(f(0.050))) print('0.025:{}'.format(f(0.025))) print('0.010:{}'.format(f(0.010))) print('0.009:{}'.format(f(0.010))) print('0.008:{}'.format(f(0.008))) print('0.007:{}'.format(f(0.007))) print('0.006:{}'.format(f(0.006))) print('0.005:{}'.format(f(0.005))) print('0.004:{}'.format(f(0.004))) print('0.003:{}'.format(f(0.003))) print('0.002:{}'.format(f(0.002))) print('0.001:{}'.format(f(0.001)))if __name__=='__main__': print('Testing busy_sleep:') test(busy_sleep) print('Testing normal_sleep:') test(normal_sleep)结果
'''DebianTesting busy_sleep:0.100:0.102237229347229010.050:0.0519969892501831040.025:0.0279969406127929670.020:0.022078318595886230.010:0.0119974517822265620.009:0.0119972229003906250.008:0.0099984407424926760.007:0.0079972791671752920.006:0.00799743652343750.005:0.0079974651336669930.004:0.0059184837341308590.003:0.0039978361129760740.002:0.00399775505065917950.001:0.003997611999511719Testing normal_sleep:0.100:0.10207970619201660.050:0.0519999885559082050.025:0.0280000019073486340.020:0.021920008659362790.010:0.0119999790191650390.009:0.0120000553131103510.008:0.0106399917602539060.007:0.0080000019073486330.006:0.007999973297119140.005:0.0080000591278076170.004:0.0061599588394165040.003:0.0040000009536743170.002:0.003999986648559570.001:0.004000091552734375$ uname -aLinux 3.2.0-4-amd64 #1 SMP Debian 3.2.57-3+deb7u2 x86_64 GNU/Linux''''''Windows 7Testing busy_sleep:0.100:0.100005722045898440.050:0.050002884864807130.025:0.02500140666961670.010:0.0105005979537963880.009:0.0105005979537963880.008:0.0080004930496215820.007:0.007400417327880860.006:0.0064002990722656250.005:0.0054003000259399420.004:0.0047003030776977540.003:0.0032001972198486330.002:0.0027001857757568360.001:0.0016000032424926759Testing normal_sleep:0.100:0.100005793571472170.050:0.05000281333923340.025:0.025001502037048340.010:0.010000491142272950.009:0.01000061035156250.008:0.0080004930496215820.007:0.0070003986358642570.006:0.0060003042221069340.005:0.005000305175781250.004:0.00400018692016601550.003:0.00300021171569824240.002:0.00200009346008300780.001:0.0010000944137573243'''实码
导入os导入wave导入sys导入io导入时间
FORMAT = 8 #get_format_from_width(2)NCHANNELS = 1FRAMERATE = 16000 # samples per secondSAMPWIDTH = 2 # bytes in a sampleBYTE_RATE = FRAMERATE*SAMPWIDTHCHUNK_DURATION = 0.020CHUNK_BYTES = int(CHUNK_DURATION*BYTE_RATE)class StreamSimulator: def __init__(self):wf = wave.open('Kalimba.wav','rb')buf = io.BytesIO()buf.write(wf.readframes(wf.getnframes()))wf.close()buf.seek(0)self.buf = bufself.step = time.time() def delay(self):#delaydelta = time.time() - self.step self.step=time.time()delay = CHUNK_DURATION - delta if delay > 0.001: time.sleep(delay) def read(self):buf = self.buf data = buf.read(CHUNK_BYTES)if len(data) == 0: buf.seek(0) data = buf.read(CHUNK_BYTES)self.delay()return data def close(self):self.buf.close()class DynamicPainter: def __init__(self):self.l=0 def paint(self,obj):str1=str(obj)l1=len(str1)bs='b'*self.lclean=' '*self.ltotal = bs+clean+bs+str1sys.stdout.write(total)sys.stdout.flush()self.l=l1if __name__=='__main__': painter = DynamicPainter() stream = StreamSimulator() produced = 0 how_many = 0 painted = time.time() while True:while time.time()-painted < 1: d = stream.read() produced += len(d) how_many += 1producing_speed = int(produced/(time.time()-painted)) painter.paint('Producing speed: {} how many: {}'.format(producing_speed,how_many))produced=0how_many=0painted = time.time()编辑
更改了“实码”,添加了包括睡眠时间在内的时间度量。但是现在我有了双字节速率:Producing speed: 63996 how many: 100这让我非常困惑。我尝试了不同的方法,最终每次都是两倍。
结论多亏@JFSebastian 和他的代码,我才知道:
最好使用截止日期作为时间参考,而不是在每个循环中创建新的参考使用截止日期可以使time.sleep的不精确度“摊销”,在所需的比特率附近振荡一点,但会得出正确的(并且要更稳定)的平均值。您只需要使用一次time.time(),这意味着更少的计算误差。结果,我得到了恒定的32000 B / s振荡到31999,很少能振荡到31745。现在我可以听到音乐了,没有任何滞后或抖动!
最终密码def read(self): buf = self.buf data = buf.read(CHUNK_BYTES) if len(data) == 0:buf.seek(0)data = buf.read(CHUNK_BYTES) self.deadline += CHUNK_DURATION delay = self.deadline - time.time() if delay > 0:time.sleep(delay) return data