IronPython NAudio Looping Crossfade Glitch

时间:2017-10-15 00:39:33

标签: ironpython naudio cross-fade

我在IronPython中使用NAudio来混合多个音频流来创建环境音频。这对于某些音轨来说效果相当不错,但对于其他音轨(风,雨),它可以在循环播放时产生震动停止/开始。

因为我不是100%确定如何在python中实现LoopStream类示例,所以我开始只是在十分之一秒或更短的时间后进行位置检查。我知道为什么我在那里有差距。从那以后,我能够弄清楚如何在python中重新创建LoopStream,并且它可以工作,但我仍然像以前一样在播放方面存在差距。我现在试图将轨道的末端交叉淡入到同一轨道的开头,当我这样做时,音频完全出现故障。
这是代码:

rawdata1$usage5 <- cut(rawdata1$Usage_Percentage,
   breaks = quantile(rawdata1$Usage_Percentage),
   include.lowest=T,labels=F)

2 个答案:

答案 0 :(得分: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个没有结果的程序中添加“结果缓冲区”,我只需要运行它们然后进行添加。交叉淡入淡出使得差距显着减少。

答案 1 :(得分: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