在 Adob​​e AIR / Actionscript 3.0 中录制 WAV - **问题**

发布于 2024-12-25 18:35:47 字数 6478 浏览 5 评论 0原文

我尝试从耳机端口直接录制到 Adob​​e Flash Builder / AIR 中的麦克风端口(使用辅助电缆),但我遇到了几个问题:

1. 录音从未发出声音与我在 iTunes 中播放的原始 MP3 文件相比,“完整”。 PCM 应该是一种未压缩的格式,因此质量应该是无损的。

2. 保存的录音(WAV)始终是我录制的长度的一半。 (例如:如果我录制一分钟,我最终会得到一个 0:30 wav 文件,而录制的后半部分不存在)

这是我正在使用的代码。有什么想法为什么我可能会遇到这些问题吗?

import com.adobe.audio.format.WAVWriter;

import flash.display.NativeWindowSystemChrome;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.filters.BitmapFilterQuality;
import flash.filters.DropShadowFilter;
import flash.media.Microphone;
import flash.media.Sound;
import flash.system.Capabilities;
import flash.utils.Timer;

import mx.controls.Alert;
import mx.core.UIComponent;
import mx.core.Window;
import mx.events.CloseEvent;

import ui.AudioVisualization;

private var shadowFilter:DropShadowFilter;
private var newWindow:Window;

// MICROPHONE STUFFZ
[Bindable] private var microphoneList:Array = Microphone.names; // Set up list of microphones
protected var microphone:Microphone;                            // Initialize Microphone
protected var isRecording:Boolean = false;                      // Variable to check if we're recording or not
protected var micRecording:ByteArray;                           // Variable to store recorded audio data

public var file:File = File.desktopDirectory;
public var stream:FileStream = new FileStream();

public var i:int = 0;
public var myTimer:Timer;


// [Start] Recording Function
protected function startMicRecording():void
{
    if(isRecording == true) stopMicRecording();
    else
    {
        consoleTA.text += "\nRecording started...";
        consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE);

        isRecording = true;
        micRecording = new ByteArray();
        microphone = Microphone.getMicrophone(comboMicList.selectedIndex);
        microphone.gain = 50;
        microphone.rate = 44;      
        microphone.setUseEchoSuppression(false); 
        microphone.setLoopBack(false);  

        // Start timer to measure duration of audio clip (runs every 1 seconds)
        myTimer = new Timer(1000);
        myTimer.start();

        // Set amount of time required to register silence
        var userSetSilence:int;
        if(splitCB.selected == true){
            userSetSilence = splitNS.value; // if checkbox is checked, use the value from the numeric stepper
        }
        else{
            userSetSilence = 2;
        }
        userSetSilence *= 100;
        microphone.setSilenceLevel(0.5, userSetSilence); // 2 seconds of silence = Register silence with onActivity (works for itunes skip)
        microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, gotMicData);
        microphone.addEventListener(ActivityEvent.ACTIVITY, this.onMicActivity);
    }
}

// [Stop] Recording Function
protected function stopMicRecording():void
{
    myTimer.stop(); // Stop timer to get final audio clip duration

    consoleTA.text += "\nRecording stopped. (" + myTimer.currentCount + "s)";
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 

    isRecording = false;
    if(!microphone) return;
    microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, gotMicData);
}

private function gotMicData(micData:SampleDataEvent):void
{
    this.visualization.drawMicBar(microphone.activityLevel,0xFF0000);
    if(microphone.activityLevel <= 5) 
    {
        consoleTA.text += "\nNo audio detected"; //trace("no music playing");
        consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 
    }
    // micData.data contains a ByteArray with our sample. 
    //Old: micRecording.writeBytes(micData.data);
    while(micData.data.bytesAvailable) { 
        var sample:Number = micData.data.readFloat(); 
        micRecording.writeFloat(sample); 
    }
}

protected function onMicActivity(event:ActivityEvent):void
{
    //trace("activating=" + event.activating + ", activityLevel=" + microphone.activityLevel);
    consoleTA.text += "\nactivating=" + event.activating + ", activityLevel=" + microphone.activityLevel;
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 

    // Mic started recording...
    if(event.activating == true)
    {
        try{
            //fs.open(file, FileMode.WRITE);
            //fs.writ
        }catch(e:Error){
            trace(e.message);
        }
    }
    // Mic stopped recording...
    if(event.activating == false)
    {
        if(file)
        {
            i++;
            myTimer.stop();
            stopMicRecording();

            if(deleteCB.selected == true)
            {

                if(myTimer.currentCount < deleteNS.value)
                {
                    consoleTA.text += "\nAudio deleted. (Reason: Too short)";
                    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 
                }
                else
                {
                    writeWav(i);
                }
            }
            else
            {
                writeWav(i);
            }

            startMicRecording();
        }
    }

}

private function save():void
{
    consoleTA.text += "\nSaving..."; //trace("file saved!");
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 

    file = new File( );
    file.browseForSave( "Save your wav" );
    file.addEventListener( Event.SELECT, writeWav );
}

public function writeWav(i:int):void
{
    var wavWriter:WAVWriter = new WAVWriter();

    // Set settings
    micRecording.position = 0;
    wavWriter.numOfChannels = 2;
    wavWriter.sampleBitRate = 16; //Audio sample bit rate: 8, 16, 24, 32
    wavWriter.samplingRate = 44100;   

    var file:File = File.desktopDirectory.resolvePath("SoundSlug Recordings/"+sessionTA.text+"_"+i+".wav");
    var stream:FileStream = new FileStream();
    //file = file.resolvePath("/SoundSlug Recordings/testFile.wav");
    stream.open( file, FileMode.WRITE );

    // convert ByteArray to WAV
    wavWriter.processSamples( stream, micRecording, 44100, 1 ); //change to 1?
    stream.close();

    consoleTA.text += "\nFile Saved: " + file.exists; //trace("saved: " + file.exists);
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE);
}      

PS:我使用的是标准 WavWriter AS 类: http://ghostcat.googlecode.com/svn-history/r424/trunk/ghostcatfp10/src/ghostcat/media/WAVWriter.as

I'm trying to record from my headphone port directly into my microphone port (using an aux cable) in Adobe Flash Builder / AIR, but I'm having a couple problems:

1. The recording never sounds "full" compared to the original MP3 file that I'm playing in iTunes. PCM is supposed to be an uncompressed format, so the quality should be lossless.

2. The saved recording (WAV) is always half the length of what I recorded.
(Example: if i record for a minute, I'll end up with a 0:30 wav file, with the second half of the recording not there)

This is the code I'm using. Any ideas why I might be encountering these problems?

import com.adobe.audio.format.WAVWriter;

import flash.display.NativeWindowSystemChrome;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.filters.BitmapFilterQuality;
import flash.filters.DropShadowFilter;
import flash.media.Microphone;
import flash.media.Sound;
import flash.system.Capabilities;
import flash.utils.Timer;

import mx.controls.Alert;
import mx.core.UIComponent;
import mx.core.Window;
import mx.events.CloseEvent;

import ui.AudioVisualization;

private var shadowFilter:DropShadowFilter;
private var newWindow:Window;

// MICROPHONE STUFFZ
[Bindable] private var microphoneList:Array = Microphone.names; // Set up list of microphones
protected var microphone:Microphone;                            // Initialize Microphone
protected var isRecording:Boolean = false;                      // Variable to check if we're recording or not
protected var micRecording:ByteArray;                           // Variable to store recorded audio data

public var file:File = File.desktopDirectory;
public var stream:FileStream = new FileStream();

public var i:int = 0;
public var myTimer:Timer;


// [Start] Recording Function
protected function startMicRecording():void
{
    if(isRecording == true) stopMicRecording();
    else
    {
        consoleTA.text += "\nRecording started...";
        consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE);

        isRecording = true;
        micRecording = new ByteArray();
        microphone = Microphone.getMicrophone(comboMicList.selectedIndex);
        microphone.gain = 50;
        microphone.rate = 44;      
        microphone.setUseEchoSuppression(false); 
        microphone.setLoopBack(false);  

        // Start timer to measure duration of audio clip (runs every 1 seconds)
        myTimer = new Timer(1000);
        myTimer.start();

        // Set amount of time required to register silence
        var userSetSilence:int;
        if(splitCB.selected == true){
            userSetSilence = splitNS.value; // if checkbox is checked, use the value from the numeric stepper
        }
        else{
            userSetSilence = 2;
        }
        userSetSilence *= 100;
        microphone.setSilenceLevel(0.5, userSetSilence); // 2 seconds of silence = Register silence with onActivity (works for itunes skip)
        microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, gotMicData);
        microphone.addEventListener(ActivityEvent.ACTIVITY, this.onMicActivity);
    }
}

// [Stop] Recording Function
protected function stopMicRecording():void
{
    myTimer.stop(); // Stop timer to get final audio clip duration

    consoleTA.text += "\nRecording stopped. (" + myTimer.currentCount + "s)";
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 

    isRecording = false;
    if(!microphone) return;
    microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, gotMicData);
}

private function gotMicData(micData:SampleDataEvent):void
{
    this.visualization.drawMicBar(microphone.activityLevel,0xFF0000);
    if(microphone.activityLevel <= 5) 
    {
        consoleTA.text += "\nNo audio detected"; //trace("no music playing");
        consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 
    }
    // micData.data contains a ByteArray with our sample. 
    //Old: micRecording.writeBytes(micData.data);
    while(micData.data.bytesAvailable) { 
        var sample:Number = micData.data.readFloat(); 
        micRecording.writeFloat(sample); 
    }
}

protected function onMicActivity(event:ActivityEvent):void
{
    //trace("activating=" + event.activating + ", activityLevel=" + microphone.activityLevel);
    consoleTA.text += "\nactivating=" + event.activating + ", activityLevel=" + microphone.activityLevel;
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 

    // Mic started recording...
    if(event.activating == true)
    {
        try{
            //fs.open(file, FileMode.WRITE);
            //fs.writ
        }catch(e:Error){
            trace(e.message);
        }
    }
    // Mic stopped recording...
    if(event.activating == false)
    {
        if(file)
        {
            i++;
            myTimer.stop();
            stopMicRecording();

            if(deleteCB.selected == true)
            {

                if(myTimer.currentCount < deleteNS.value)
                {
                    consoleTA.text += "\nAudio deleted. (Reason: Too short)";
                    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 
                }
                else
                {
                    writeWav(i);
                }
            }
            else
            {
                writeWav(i);
            }

            startMicRecording();
        }
    }

}

private function save():void
{
    consoleTA.text += "\nSaving..."; //trace("file saved!");
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE); 

    file = new File( );
    file.browseForSave( "Save your wav" );
    file.addEventListener( Event.SELECT, writeWav );
}

public function writeWav(i:int):void
{
    var wavWriter:WAVWriter = new WAVWriter();

    // Set settings
    micRecording.position = 0;
    wavWriter.numOfChannels = 2;
    wavWriter.sampleBitRate = 16; //Audio sample bit rate: 8, 16, 24, 32
    wavWriter.samplingRate = 44100;   

    var file:File = File.desktopDirectory.resolvePath("SoundSlug Recordings/"+sessionTA.text+"_"+i+".wav");
    var stream:FileStream = new FileStream();
    //file = file.resolvePath("/SoundSlug Recordings/testFile.wav");
    stream.open( file, FileMode.WRITE );

    // convert ByteArray to WAV
    wavWriter.processSamples( stream, micRecording, 44100, 1 ); //change to 1?
    stream.close();

    consoleTA.text += "\nFile Saved: " + file.exists; //trace("saved: " + file.exists);
    consoleTA.scrollToRange(int.MAX_VALUE, int.MAX_VALUE);
}      

PS: I'm using the standard WavWriter AS class: http://ghostcat.googlecode.com/svn-history/r424/trunk/ghostcatfp10/src/ghostcat/media/WAVWriter.as

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝眼泪 2025-01-01 18:35:47

是的,耳机麦克风有问题。您仅通过耳机插孔发送一小部分数据。它已被净化、重组、减少或限制,以使聆听体验不间断地进行(一个关键的体验因素)。记录下来会给你带来一堆泥巴。为了录制完美的音频,您必须使用音频数据本身,而不是依赖于程序的输出,这些程序(真诚地)致力于实现完美数字再现之外的其他目标。

但不确定为什么音频只有一半。

Yeah, the headphone to mic is the problem. You are sending only a fraction of the data through the headphone jack. It has been sanitized, restructured, reduced or throttled to make the listening experience work without interruptions (a critical experiential factor). To record that will give you a bunch of mud. In order to record perfect audio, you have to work with the audio data itself, and not rely on output from programs which are (sincerely) working toward other goals than perfect digital reproduction.

Not sure why the audio is only half, though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文