2017-10-15 255 views
0

我在IronPython中使用NAudio混合多个音频流来创建环境音频。这对于某些曲目来说工作得相当好,但对于其他一些曲目(风,雨),循环播放时可能会产生刺耳的停止/开始。IronPython NAudio循环交叉淡入淡出

因为我并不是100%确定如何在python中实现LoopStream类的例子,所以我开始在十分之一秒或更短的时间内完成位置检查。我知道我为什么在那里有空位。从那以后,我能够弄清楚如何在python中重新创建LoopStream,并且它可以工作,但是我仍然像以前一样在回放中存在差距。我正在尝试将曲目的末尾逐渐淡入相同曲目的开头,当我这样做时,音频完全消失。
下面的代码:

class LoopStream(WaveStream): 
    def __init__(self,WaveStream,AudioStream): 
    self.wavestream = WaveStream 
    self.audiostream = AudioStream  
    def get_WaveFormat(self): 
    return self.wavestream.WaveFormat 
    def get_Length(self): 
    return self.wavestream.Length 
    def get_Position(self): 
    return self.wavestream.Position 
    def HasData(count): 
    return True 

    def Read(self,buf,offset,count):  
    read = 0 
    while(read < count):    
     required = count - read 
     #print(str(self.audiostream.get_chan_id()) + " reading @ " + str(self.wavestream.Position) + "/" + str(self.wavestream.Length)) 
     pos = self.wavestream.Position 
     readthistime = self.wavestream.Read(buf,offset+read,required) 
     if pos == 0: 
     self.startbuf = buf  
     if readthistime < required: 
     self.wavestream.Position = 0 
     #print(len(buf)) 
     #buf = buf+self.startbuf    
     print(len(buf)) 
     buf = FadeOut(self,buf,offset,readthistime) + FadeIn(self,self.startbuf,0,required) 
     print(len(buf)) 
     readthistime+=required 
     print(str(self.audiostream.get_chan_id()) + " restarting1") 
     elif self.wavestream.Position + required > self.wavestream.Length:   
     #read += readthistime 
     #readthistime = self.wavestream.Read(buf,self.wavestream.Position,required) 
     #print(str(self.audiostream.get_chan_id()) + " restarting2") 
     pass 
     if self.wavestream.Position >= self.wavestream.Length: 
     self.wavestream.Position = 0 
     buf = buf + self.startbuf 
     print(str(self.audiostream.get_chan_id()) + " restarting3") 
     read += readthistime 
    return read 

    def FadeOut(self,buf,offset,count): 
    sample = 0 
    maxfadesamples = int((self.wavestream.WaveFormat.SampleRate * 75)/1000) 
    fadesamples = 0 
    while sample < count: 
     multiplier = 1.0 - (fadesamples/maxfadesamples) 
     for i in range(0,self.wavestream.WaveFormat.Channels):  
     buf[offset+sample] *= multiplier 
     sample+=1 
     fadesamples+=1 

     if fadesamples > maxfadesamples: 
     for j in range(0,self.wavestream.WaveFormat.Channels): 
      while sample < count: 
      buf[offset+sample] = 0 
      sample+=1 
    def FadeOut(self,buf,offset,count): 
    sample = 0  
    maxfadesamples = int((self.wavestream.WaveFormat.SampleRate * 75)/1000) 
    fadesamples = 0 
    while sample < count: 
     multiplier = (fadesamples/maxfadesamples) 
     for i in range(0,self.wavestream.WaveFormat.Channels): 
     buf[offset+sample] *= multiplier 
     sample+=1 
     fadesamples+=1 
+0

ERR ..已经注意到我只是需要习惯于在这里..添加错误处理语句,因为我发布后,立即发现了一些问题,所以我最终可能会解决自己1)淡出声明的两倍,因此FadeIn实际上并不存在。一旦我将FadeOut#2重命名为FadeIn,它仍然有毛病,但因为它陷入了无限循环。我解决了这个问题,但仍然存在问题,但我认为它在读取功能的其他地方出错。 –

回答

0

对不起,问愚蠢的问题....应该是很明显的,我用没有返回缓冲区,但只作用于传递给他们一个缓冲液的功能。

所以溶液容易确定的,一旦我得到了一个很好的错误消息

这条线:

buf = FadeOut(self,buf,offset,readthistime) + FadeIn(self,self.startbuf,0,required) 

变成了:

try: 
    self.FadeOut(buf,offset,readthistime) 
    self.FadeIn(self.startbuf,0,required) 
    buf = buf = self.startbuf 
except Exception, e: 
    print(repr(e)) 

所以,问题是,我尝试添加“结果缓冲区“从2个程序没有结果,我只需要运行它们,然后添加。交叉淡入使得差距显着不明显。

0

下面是一个比我以前的尝试更好的解决方案,这一个交叉淡入淡出而不是淡入淡出,这确实减少了差距,但对于某些音轨重启仍然是一个明显的故障。

class LoopStream(WaveStream): 
    def __init__(self,WaveStream,AudioStream): 
    self.wavestream = WaveStream 
    self.originalstream = self.wavestream 
    self.audiostream = AudioStream 

    if (float(self.get_Length())/self.WaveFormat.AverageBytesPerSecond) > 6: 
     self.CFSeconds = 3.1 
    else: 
     #self.CFSeconds = (self.LSeconds/2.0) + 0.1 
     self.CFSeconds = ((float(self.get_Length())/self.WaveFormat.AverageBytesPerSecond)/2) - 0.1 
    self.CFBytes = int(round(self.WaveFormat.AverageBytesPerSecond*self.CFSeconds)) 
    #determine bytes per section of audio 
    temp = (self.WaveFormat.BitsPerSample/8) * self.WaveFormat.Channels 
    #determine how many bytes we are over target 
    temp = self.CFBytes % temp 
    #subtract bits to get to target 
    self.CFBytes-=temp 

    self.startbuf = Array.CreateInstance(System.Byte,self.CFBytes) 
    self.endbuf = Array.CreateInstance(System.Byte,self.CFBytes) 
    self.wavestream.Read(self.startbuf,0,self.CFBytes) 
    self.wavestream.Position = self.Length - self.CFBytes 
    self.wavestream.Read(self.endbuf,0,self.CFBytes) 

    self.wavestream.Position = 0 

    #self.startbuf = self.buf[:int(round(self.WaveFormat.AverageBytesPerSecond*CFSeconds))]   
    self.FadeIn(self.startbuf,0,int(round(self.WaveFormat.AverageBytesPerSecond*self.CFSeconds)))  

    #self.endbuf = self.buf[self.Length-int(round(self.WaveFormat.AverageBytesPerSecond*CFSeconds)):] 
    self.FadeOut(self.endbuf,0,int(round(self.WaveFormat.AverageBytesPerSecond*self.CFSeconds))) 
    self.FirstPlay = True 

    self.startstream = RawSourceWaveStream(self.startbuf,0,self.CFBytes,self.WaveFormat) 
    self.endstream = RawSourceWaveStream(self.endbuf,0,self.CFBytes,self.WaveFormat) 
    self.crossfadestream = MixingWaveProvider32() #self.startstream,self.endstream) 
    self.crossposition = 0 
    self.crossfadestream.AddInputStream(self.startstream) 
    self.crossfadestream.AddInputStream(self.endstream) 
    self.CFBuffer = Array.CreateInstance(System.Byte,self.CFBytes) 
    self.crossfadestream.Read(self.CFBuffer,0,self.CFBytes) 

    print(self.audiostream.chan_id,"initialized") 
    def get_WaveFormat(self): 
    return self.wavestream.WaveFormat 
    def get_Length(self): 
    return self.wavestream.Length 
    def get_Position(self): 
    return self.wavestream.Position 
    def HasData(count): 
    return True 
    def LSeconds(self): 
    return float(self.get_Length())/self.WaveFormat.AverageBytesPerSecond 
    def PSeconds(self): 
    return float(self.get_Position())/self.WaveFormat.AverageBytesPerSecond 
    def Read(self,buf,offset,count):  
    read = 0 
    while(read < count):    
     required = count - read 
     readthistime = 0 
     if self.FirstPlay == True: 
     if (int(self.Position) + read >= self.CFBytes) or (int(self.Position) + read >= int(self.Length) - self.CFBytes): 
      self.FirstPlay = False 

     if self.FirstPlay == True or ((int(self.Position) + read) < (int(self.Length) - self.CFBytes) and (int(self.Position) + read > self.CFBytes)):     
     try: 
      #print(self.audiostream.chan_id,"Normal") 
      readthistime = self.wavestream.Read(buf,offset+read,required)   
     except Exception, e: 
      exc_type, exc_obj, exc_tb = sys.exc_info() 
      fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 
      print(exc_type,fname,exc_tb.tb_lineno) 
     else:  
     try:   
      #print(self.audiostream.chan_id,"Crossfade") 
      buf = self.CFBuffer 
      self.wavestream.Position = self.CFBytes + ((self.WaveFormat.BitsPerSample/8)*self.WaveFormat.Channels) 
      read += self.CFBytes   
      return read 
     except Exception, e: 
      exc_type, exc_obj, exc_tb = sys.exc_info() 
      fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 
      print(exc_type,fname,exc_tb.tb_lineno) 
     read += readthistime 
    return read 

    def FadeOut(self,buf,offset,count):  
    sample = 0 
    maxfadesamples = int((self.WaveFormat.SampleRate * self.CFSeconds)) 
    fadesamples = 0 
    while sample < count: 
     multiplier = 1.0 - (fadesamples/maxfadesamples) 
     for i in range(0,self.wavestream.WaveFormat.Channels):  
     try:   
      buf[offset+sample] *= multiplier   
     except Exception, e: 
      exc_type, exc_obj, exc_tb = sys.exc_info() 
      fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 
      print(sample,exc_type,fname,exc_tb.tb_lineno) 
      return 
     sample+=1 
     fadesamples+=1 

     if fadesamples > maxfadesamples:   
     while sample < count:   
      buf[offset+sample] = 0   
      sample+=1 
     break 
    def FadeIn(self,buf,offset,count):  
    sample = 0  
    maxfadesamples = int((self.WaveFormat.SampleRate * self.CFSeconds)) 
    fadesamples = 0 
    while sample < count:  
     multiplier = (fadesamples/maxfadesamples) 
     for i in range(0,self.wavestream.WaveFormat.Channels): 
     buf[offset+sample] *= multiplier 
     sample+=1 
     fadesamples+=1 
     if fadesamples>maxfadesamples: 
     break