Actionscript 3 生成的音频没有循环存储在ByteArray中并加载到声音对象中?

Actionscript 3 生成的音频没有循环存储在ByteArray中并加载到声音对象中?,actionscript-3,audio,Actionscript 3,Audio,编辑2:这个问题仍然存在,但似乎是一个bug。AdobeSound类在加载ByteArray后不发送Sound.length值。这是我提交的bug报告(请投赞成票!) ===== 下面的代码只产生一次声音——它播放正确的声音,但不循环。我认为应该这样。我似乎无法调试它 它似乎也不会给整个事件带来好的结果。我是不是遗漏了什么 编辑:仍然是坏的,但我更新了下面的代码,所以你可以测试它。只需复制到类并调用testSound(): private var NUM_SAMPLES:int=16384*2

编辑2:这个问题仍然存在,但似乎是一个bug。Adobe
Sound
类在加载
ByteArray
后不发送
Sound.length
值。这是我提交的bug报告(请投赞成票!)

=====

下面的代码只产生一次声音——它播放正确的声音,但不循环。我认为应该这样。我似乎无法调试它

它似乎也不会给整个事件带来好的结果。我是不是遗漏了什么

编辑:仍然是坏的,但我更新了下面的代码,所以你可以测试它。只需复制到类并调用
testSound()

private var NUM_SAMPLES:int=16384*2;
私人银行:ByteArray;
私有var卷:数量=1;
私有变量通道:SoundChannel=新的SoundChannel();
私人风险值率:int=44100;
公共函数testSound():void
{
var baseSound:Sound=新声音();
storeAudio();
var trans:SoundTransform=新的SoundTransform(音量,0);
SoundMixer.soundTransform=trans;
soundByteArray.position=0;
baseSound.loadPCMFromByteArray(soundByteArray,NUM_样本,“float”,true,RATE);
soundByteArray.position=0;
baseSound.addEventListener(flash.events.Event.SOUND_COMPLETE,onPlaybackComplete);
记录道(“加载1:+baseSound.长度);
跟踪(“加载2:+基音。字节加载”);
跟踪(“加载3:+baseSound.ByTestTotal”);
通道=基音。播放(0,20,trans);
channel.addEventListener(flash.events.Event.SOUND_COMPLETE,onPlaybackComplete);
}
播放完成时受保护的函数(事件:flash.events.event):无效
{
跟踪(“onPlaybackComplete”+通道位置);
}
私有函数storeAudio():void
{
soundByteArray=新的ByteArray();
对于(变量i:Number=0;i
好的,我很感谢您将此问题视为一个bug并可能继续。然而,我使用了一个小黑客来重播loadPCMFromByteArray。不要依赖
声音。完成
只需编写知道何时完全达到PCM音频字节长度的代码

通过
将字节长度转换为毫秒
并使用
channel.position
您将获得与.Complete功能基本相同的结果(如果我在这里出错,任何人都可以纠正我)。如果您确实需要触发事件,即为了某些依赖于该反馈的功能,那么您只需发送您自己的自定义事件并监听该事件,而不是
声音。完成

从测试中,我认为持续的小故障/咔哒声实际上是Flash试图向前播放声音,但不会移动到PCM数据的最后字节。 可以将其视为ByteArray中发现的E-O-F错误的一个非常听得见的版本,但也可以从内部运行(永不结束?
而循环
只是为了愉悦您的耳朵

代码前的一些注意事项:

  • 在测量音结束时,我试着<代码>soundByteArray.position=0不好!channel.position跟踪显示为卡在结束pos金额上。也试过
    channel=baseSound.play(0)不好<代码>频道。位置
    轨迹显示为卡在零位置。两者都发出了口吃声

  • 此外,虽然我这次没有尝试,但我以前循环过sampleData,没有出现故障,因此我确信值得考虑将PCM复制到sampleData设置中,并查看循环和触发声音是否更有效。完成等

如果只是简单的音调生成和循环,您甚至不需要使用PCMdata,只需使用sampleData作为第一选择就可以进行动态声音生成。然而,如果你涉及到人声或乐队音乐的PCM样本,那么你将需要下面的技巧在声音结束时重播

不管怎样,现在这里有一些代码演示来说明循环黑客

 package  
 {

    import flash.display.MovieClip;
    import flash.events.*;
    import flash.utils.*;
    import flash.media.*;
    import flash.text.*;

 public class testSound extends MovieClip 
 {

    private var BIT_TYPE:int = 16; //16bit audio
    private var RATE:int = 44100; 
    private var NUM_SAMPLES:int = 8192; //16384 * 2;
    private var NUM_CHANNEL:int = 2; //if stereo 
    private var NUM_TEMP:int =0; //adjustable number for test without changing others 

    public var NUM_TONE_FREQ:int = 440;

    private var soundByteArray:ByteArray;
    private var volume:Number = 1;
    private var channel:SoundChannel = new SoundChannel();


    public var final_samples:int = 0;
    public var time_total:Number; //dont use Integers here - wont always be correct
    public var time_kbps:Number; //"bytes per second" count 

    public var loop_count:int = 0;
    public var timerCount:Number = 0;
    public var timerSecs:Number = 0;
    public var timer:Timer;

    public var trans:SoundTransform;
    public var baseSound:Sound = new Sound(); 

    public var timeText:TextField;
    public var txtFormat:TextFormat;

    public function testSound():void
    {
        //correct NUM_SAMPLES helps with end-time check
        NUM_SAMPLES *= NUM_CHANNEL * BIT_TYPE;

        trans = new SoundTransform(volume, 0);
        channel.soundTransform = trans;  //SoundMixer.soundTransform = trans;

        soundByteArray = new ByteArray();
        soundByteArray.position = 0;

        //setup textField for debug feedback
        setupTextFBack();

        //generate PCM
        storeAudio();
    }

    protected function onPlaybackComplete(event:flash.events.Event):void
    {
        //only works if you are passing your PCM to sampleData events, 
        trace("onPlaybackComplete" + channel.position);
    }

    private function storeAudio():void
    {

       for (var i:Number = 0; i < NUM_SAMPLES; i++) 
        {
            soundByteArray.writeFloat
            (  Math.sin((i / RATE) * Math.PI * 2 * NUM_TONE_FREQ)  );

           soundByteArray.writeFloat
           (  Math.sin((i / RATE) * Math.PI * 2 * NUM_TONE_FREQ)  );

        }

        trace("storeAudio samples (i) = " + i + ", ByteArray length: " + soundByteArray.length);

        final_samples = i;
        playAudio();
    }

    public function playAudio():void
    {

        soundByteArray.position = 0;
        baseSound.loadPCMFromByteArray(soundByteArray, final_samples, "float", true, RATE);

        channel = baseSound.play(); //channel = baseSound.play(0, 0, trans);
        setupTimeCount(); //count when play starts

        time_kbps = (RATE *  NUM_CHANNEL * BIT_TYPE) / 4; //not /8 because time is never doubled on stereo 
        time_total = (soundByteArray.length / time_kbps);
        time_total = Math.round(time_total * 100) / 100;

        trace ("=== DEBUG INFO : (loop: "+loop_count+ ") =========================================");
        trace ("*** Playing beyond Total Time (PCM end) creates sound glitch issues ");
        trace ("*** Re-Play on a continous Tone will creates short click when it stops to replay ");
        trace ("*** If PCM was music/vocals this click might not be perceived by ear if looped right");
        trace ("====================================================================");
        trace ("Total Kb/sec : " + time_kbps + " bytes per sec");
        trace ("Total time   : " + time_total + " secs" );

        //trim Total millisecs just to avoid any glitches/clicks. Test & fine-tune
        time_total -= 0.314; //PI divided by 10. Need fine-tune? Hell Yes!

        trace ("Total (trim) : " + time_total + " secs" );
    }

    public function setupTimeCount():void
    {
        timer = new Timer(100);
        timer.addEventListener(TimerEvent.TIMER, timerHandler);
        timerCount = 0;
        timer.start();
    }

    function timerHandler(Event:TimerEvent):void
    {
        timerCount += 100;
        checkTime(timerCount);
        //trace("channel.pos = " + channel.position); //for debug only
    }

    function checkTime(miliseconds:int) : void 
    {
        timerSecs = miliseconds/1000;
        timeText.text = ("elapsed : " + timerSecs);

        //if (timerSecs >= time_total)
        if ( channel.position >= (time_total * 1000) )
        {
            reloopAudio();
        }
    }

    function reloopAudio():void
    {
            channel.stop(); //else you get stutter from going forward
            timer.stop();
            trace("attempting replay / loop..");
            loop_count += 1;
            playAudio(); //redo playing function
    }

    public function setupTextFBack():void
    {
        txtFormat = new TextFormat();
        txtFormat.size = 20; 
        txtFormat.font = "Arial"; 

        timeText = new TextField();
        timeText.defaultTextFormat = txtFormat;
        timeText.antiAliasType = AntiAliasType.ADVANCED;

        timeText.x = stage.stageWidth / 2 ;
        timeText.y = stage.stageHeight / 2 ;
        timeText.textColor = 0xFF0000;
        timeText.text = " ";
        timeText.width = 200;

        addChild(timeText);

    }

 }
 }
包
{
导入flash.display.MovieClip;
导入flash.events.*;
导入flash.utils。*;
导入flash.media.*;
导入flash.text.*;
公共类testSound扩展了MovieClip
{
私有变量位类型:int=16;//16位音频
私人风险值率:int=44100;
私有变量NUM_SAMPLES:int=8192;//16384*2;
专用var NUM_通道:int=2;//如果立体声
private var NUM_TEMP:int=0;//在不更改其他值的情况下,测试的可调整值
公共变量NUM\u TONE\u FREQ:int=440;
私人银行:ByteArray;
私有var卷:数量=1;
私有变量通道:SoundChannel=新的SoundChannel();
公共var最终样本:int=0;
public var time\u total:Number;//此处不要使用整数-不会总是正确的
公共变量时间\u kbps:Number;/“每秒字节数”计数
公共变量循环计数:int=0;
公共变量timerCount:Number=0;
公共变量timerSecs:Number=0;
公共变量计时器:计时器;
公共变量转换:声音转换;
public var baseSound:Sound=新声音();
公共变量timeText:TextField;
公共变量txtFormat:TextFormat;
公共函数testSound():void
{
//正确的NUM_示例有助于结束时间检查
NUM_SAMPLES*=NUM_信道*位类型;
trans=新的声音转换(音量,0);
channel.soundTransform=trans;//SoundMixer.soundTransform=trans;
soundByteArray=新的ByteArray();
soundByteArray.position=0;
//调试反馈的设置文本字段
setupTextFBack();
//生成PCM
storeAudio();
}
 package  
 {

    import flash.display.MovieClip;
    import flash.events.*;
    import flash.utils.*;
    import flash.media.*;
    import flash.text.*;

 public class testSound extends MovieClip 
 {

    private var BIT_TYPE:int = 16; //16bit audio
    private var RATE:int = 44100; 
    private var NUM_SAMPLES:int = 8192; //16384 * 2;
    private var NUM_CHANNEL:int = 2; //if stereo 
    private var NUM_TEMP:int =0; //adjustable number for test without changing others 

    public var NUM_TONE_FREQ:int = 440;

    private var soundByteArray:ByteArray;
    private var volume:Number = 1;
    private var channel:SoundChannel = new SoundChannel();


    public var final_samples:int = 0;
    public var time_total:Number; //dont use Integers here - wont always be correct
    public var time_kbps:Number; //"bytes per second" count 

    public var loop_count:int = 0;
    public var timerCount:Number = 0;
    public var timerSecs:Number = 0;
    public var timer:Timer;

    public var trans:SoundTransform;
    public var baseSound:Sound = new Sound(); 

    public var timeText:TextField;
    public var txtFormat:TextFormat;

    public function testSound():void
    {
        //correct NUM_SAMPLES helps with end-time check
        NUM_SAMPLES *= NUM_CHANNEL * BIT_TYPE;

        trans = new SoundTransform(volume, 0);
        channel.soundTransform = trans;  //SoundMixer.soundTransform = trans;

        soundByteArray = new ByteArray();
        soundByteArray.position = 0;

        //setup textField for debug feedback
        setupTextFBack();

        //generate PCM
        storeAudio();
    }

    protected function onPlaybackComplete(event:flash.events.Event):void
    {
        //only works if you are passing your PCM to sampleData events, 
        trace("onPlaybackComplete" + channel.position);
    }

    private function storeAudio():void
    {

       for (var i:Number = 0; i < NUM_SAMPLES; i++) 
        {
            soundByteArray.writeFloat
            (  Math.sin((i / RATE) * Math.PI * 2 * NUM_TONE_FREQ)  );

           soundByteArray.writeFloat
           (  Math.sin((i / RATE) * Math.PI * 2 * NUM_TONE_FREQ)  );

        }

        trace("storeAudio samples (i) = " + i + ", ByteArray length: " + soundByteArray.length);

        final_samples = i;
        playAudio();
    }

    public function playAudio():void
    {

        soundByteArray.position = 0;
        baseSound.loadPCMFromByteArray(soundByteArray, final_samples, "float", true, RATE);

        channel = baseSound.play(); //channel = baseSound.play(0, 0, trans);
        setupTimeCount(); //count when play starts

        time_kbps = (RATE *  NUM_CHANNEL * BIT_TYPE) / 4; //not /8 because time is never doubled on stereo 
        time_total = (soundByteArray.length / time_kbps);
        time_total = Math.round(time_total * 100) / 100;

        trace ("=== DEBUG INFO : (loop: "+loop_count+ ") =========================================");
        trace ("*** Playing beyond Total Time (PCM end) creates sound glitch issues ");
        trace ("*** Re-Play on a continous Tone will creates short click when it stops to replay ");
        trace ("*** If PCM was music/vocals this click might not be perceived by ear if looped right");
        trace ("====================================================================");
        trace ("Total Kb/sec : " + time_kbps + " bytes per sec");
        trace ("Total time   : " + time_total + " secs" );

        //trim Total millisecs just to avoid any glitches/clicks. Test & fine-tune
        time_total -= 0.314; //PI divided by 10. Need fine-tune? Hell Yes!

        trace ("Total (trim) : " + time_total + " secs" );
    }

    public function setupTimeCount():void
    {
        timer = new Timer(100);
        timer.addEventListener(TimerEvent.TIMER, timerHandler);
        timerCount = 0;
        timer.start();
    }

    function timerHandler(Event:TimerEvent):void
    {
        timerCount += 100;
        checkTime(timerCount);
        //trace("channel.pos = " + channel.position); //for debug only
    }

    function checkTime(miliseconds:int) : void 
    {
        timerSecs = miliseconds/1000;
        timeText.text = ("elapsed : " + timerSecs);

        //if (timerSecs >= time_total)
        if ( channel.position >= (time_total * 1000) )
        {
            reloopAudio();
        }
    }

    function reloopAudio():void
    {
            channel.stop(); //else you get stutter from going forward
            timer.stop();
            trace("attempting replay / loop..");
            loop_count += 1;
            playAudio(); //redo playing function
    }

    public function setupTextFBack():void
    {
        txtFormat = new TextFormat();
        txtFormat.size = 20; 
        txtFormat.font = "Arial"; 

        timeText = new TextField();
        timeText.defaultTextFormat = txtFormat;
        timeText.antiAliasType = AntiAliasType.ADVANCED;

        timeText.x = stage.stageWidth / 2 ;
        timeText.y = stage.stageHeight / 2 ;
        timeText.textColor = 0xFF0000;
        timeText.text = " ";
        timeText.width = 200;

        addChild(timeText);

    }

 }
 }