ActionScript 3.0播放16位小端立体声PCM音频的问题求助
解决方案:Flash/AIR AS3播放16bit小端立体声PCM音频
核心问题分析
你遇到的问题核心是PCM数据格式与AS3的Sound类、SampleDataEvent要求不匹配:
- 16bit小端PCM需转换为**-1.0到1.0之间的浮点值**才能被AS3音频系统识别
- 立体声数据必须按左、右声道交替输出
- 读取文件时需确保字节序为小端(AS3的
readShort()默认支持小端,无需额外处理)
跨Flash/AIR的文件/文件夹读取实现
以下代码兼容Flash Player和AIR,支持单个PCM文件读取(Flash)、文件夹及一级子文件夹遍历读取(AIR):
import flash.filesystem.*; import flash.net.FileReference; import flash.events.Event; import flash.events.SampleDataEvent; import flash.media.Sound; import flash.system.Capabilities; var pcmData:ByteArray; var sound:Sound; // 根据运行环境选择文件/文件夹选择逻辑 if (Capabilities.playerType == "AIR") { var airFolder:File = File.documentsDirectory; airFolder.browseForDirectory("选择音频文件夹"); airFolder.addEventListener(Event.SELECT, onAIRFolderSelect); } else { var flashFileRef:FileReference = new FileReference(); flashFileRef.browse([new FileFilter("PCM音频文件", "*.pcm")]); flashFileRef.addEventListener(Event.SELECT, onFlashFileSelect); } // Flash环境:单个文件读取 function onFlashFileSelect(e:Event):void { var fr:FileReference = e.target as FileReference; fr.addEventListener(Event.COMPLETE, onFileLoaded); fr.load(); } // AIR环境:遍历文件夹及一级子文件夹 function onAIRFolderSelect(e:Event):void { var targetFolder:File = e.target as File; var fileList:Array = targetFolder.getDirectoryListing(); for each (var item:File in fileList) { if (item.isDirectory) { var subFileList:Array = item.getDirectoryListing(); for each (var subItem:File in subFileList) { if (subItem.extension.toLowerCase() == "pcm") loadAIRPCMFile(subItem); } } else if (item.extension.toLowerCase() == "pcm") { loadAIRPCMFile(item); } } } // AIR环境读取单个PCM文件 function loadAIRPCMFile(file:File):void { var stream:FileStream = new FileStream(); stream.open(file, FileMode.READ); pcmData = new ByteArray(); stream.readBytes(pcmData); stream.close(); playTargetPCM(); } // Flash环境文件加载完成回调 function onFileLoaded(e:Event):void { pcmData = (e.target as FileReference).data; playTargetPCM(); }
正确的PCM音频播放逻辑
这段代码严格处理16bit小端立体声数据的格式转换,解决噪音、播放异常问题:
function playTargetPCM():void { sound = new Sound(); sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onPCMSampleData); // 重置ByteArray指针到起始位置 pcmData.position = 0; sound.play(); } function onPCMSampleData(e:SampleDataEvent):void { // 每次事件需输出2048个样本(对应1024帧,每帧含左、右声道各一个样本) var requiredSamples:int = 2048; var writtenSamples:int = 0; while (pcmData.bytesAvailable > 0 && writtenSamples < requiredSamples) { // 读取左声道16bit小端值,转换为-1.0~1.0的浮点 var leftRaw:int = pcmData.readShort(); var leftFloat:Number = leftRaw / 32768; // 读取右声道16bit小端值,转换为-1.0~1.0的浮点 var rightRaw:int = pcmData.readShort(); var rightFloat:Number = rightRaw / 32768; // 按左、右顺序写入样本 e.data.writeFloat(leftFloat); e.data.writeFloat(rightFloat); writtenSamples += 2; } // 数据读取完毕后移除事件监听,停止播放 if (pcmData.bytesAvailable == 0) { sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, onPCMSampleData); } }
常见问题修正说明
- 循环次数异常:你看到的1024次循环是正常的——每次循环处理2个样本(左+右),2048个总样本刚好对应1024次循环。
- 噪音问题:
- 必须用
readShort()读取小端数据,不要手动反转字节顺序 - 转换浮点值时必须除以32768(16bit有符号整数的最大值),超出范围会导致音频失真
- 严格按照左、右声道的顺序写入样本,与PCM文件的声道顺序保持一致
- 必须用
- AIR运行问题:在Flash CS6发布AIR应用时,需确保配置正确的AIR证书,并在应用描述文件中开启文件系统访问权限。
内容的提问来源于stack exchange,提问作者Klymins
相关产品推荐
相关产品推荐

