adobe air で作成したアプリケーションを xamarin に移植したいと考えています。その理由は、flex フレームワークを使用して iPod ライブラリから mp3 を取得できなかったためです。これでオーディオ ファイルのリストを取得できますが、アセットからオーディオ バッファを抽出するのに問題があります。AS3 ではブラック ボックスですが、データは常に次のプロパティを持つバイト配列としてエクスポートされます。
- サンプリングレート 44100Hz
- 32ビット
- 浮動小数点
- ステレオ
すべてのアルゴリズムを書き直すわけにはいかないので、すべての曲を AIR と同じ形式で「変換」したいと考えています。だから私はこれを書いた
AVAsset urlAsset = AVUrlAsset.FromUrl (url);
NSError error = null;
AVAssetReader reader = new AVAssetReader (urlAsset, out error);
AVAssetTrack[] tracks = urlAsset.TracksWithMediaType (AVMediaType.Audio);
NSMutableDictionary audioReadSettings = new NSMutableDictionary ();
audioReadSettings.SetValueForKey (NSNumber.FromObject(AudioFormatType.LinearPCM), AVAudioSettings.AVFormatIDKey);
audioReadSettings.SetValueForKey (NSNumber.FromBoolean(false), AVAudioSettings.AVLinearPCMIsBigEndianKey);
audioReadSettings.SetValueForKey (NSNumber.FromBoolean(true), AVAudioSettings.AVLinearPCMIsFloatKey);
audioReadSettings.SetValueForKey (NSNumber.FromBoolean(false), AVAudioSettings.AVLinearPCMIsNonInterleaved);
audioReadSettings.SetValueForKey ((NSNumber)32, AVAudioSettings.AVLinearPCMBitDepthKey);
/*
audioReadSettings.SetValueForKey ((NSNumber)2, AVAudioSettings.AVNumberOfChannelsKey);
audioReadSettings.SetValueForKey ((NSNumber)44100.0, AVAudioSettings.AVSampleRateKey);
*/
AVAssetTrack track = tracks[0];
AVAssetReaderTrackOutput outputReader = AVAssetReaderTrackOutput.FromTrack (track, audioReadSettings);
if (!reader.CanAddOutput(outputReader)){
return;
}
reader.AddOutput(outputReader);
outputReader.Dispose();
double sampleRate = 0;
int channelCount = 0;
foreach (CMFormatDescription formatDescription in track.FormatDescriptions){
if (formatDescription.AudioFormats.Length != 0){
AudioFormat format = formatDescription.AudioFormats[0];
sampleRate = format.AudioStreamBasicDescription.SampleRate;
channelCount = format.AudioStreamBasicDescription.ChannelsPerFrame;
break;
}
}
int bytesPerSample = 2 * channelCount;
outputReader = (AVAssetReaderTrackOutput)reader.Outputs[0];
if (!reader.StartReading()){
return;
}
List flatBuffer = new List();
List> buffers = new List>();
string bufferString = string.Empty;
for (int i = 0; i < 16; i++){
CMSampleBuffer sampleBuffer = outputReader.CopyNextSampleBuffer();
List buffer = extractBuffer(sampleBuffer, i, bytesPerSample, channelCount);
flatBuffer.AddRange (buffer);
sampleBuffer.Dispose();
}
そして、extractBuffer メソッドは次のようになります
private List extractBuffer(CMSampleBuffer sampleBuffer, int index, int bytesPerSamples, int channelCount){
CMBlockBuffer blockBuffer = sampleBuffer.GetDataBuffer ();
int dataLength = (int)blockBuffer.DataLength;
NSMutableData data = NSMutableData.FromLength (dataLength);
blockBuffer.CopyDataBytes (0, (uint)dataLength, data.MutableBytes);
int sampleCount = sampleBuffer.NumSamples;
float[] resultBuffer = new float[sampleCount];
unsafe{
float* samples = (float*)data.MutableBytes;
for (int i = 0; i < sampleCount; i++){
float left = (float)*samples++;
float right = left;
if (channelCount == 2){
right = (float)*samples++;
}
resultBuffer [i] = (float)((left + right) / 2);
}
}
List result = new List(resultBuffer);
resultBuffer = null;
blockBuffer.Dispose ();
blockBuffer = null;
return result;
}
後で分析するために、信号をモノとして再変換することに注意してください。
これで、同じ mp3 に対して xamarin と adobe air の同じデータを取得する必要がありますが、そうではありません。ほとんどの場合、同じ値を取得しますが、同じインデックスでは取得しません。adobe のエンジニアは何をしているのかを知っていると思いますが、ここで何を見逃したのでしょうか?
ご協力いただきありがとうございます