2017-10-15 149 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