回答
這是我的代碼,用於從函數生成聲音。我假設你知道如何使用AudioQueue服務,設置AudioSession,並正確啓動和停止音頻輸出隊列。
這裏的設立和啓動輸出AudioQueue一個片段:
// Get the preferred sample rate (8,000 Hz on iPhone, 44,100 Hz on iPod touch)
size = sizeof(sampleRate);
err = AudioSessionGetProperty (kAudioSessionProperty_CurrentHardwareSampleRate, &size, &sampleRate);
if (err != noErr) NSLog(@"AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate) error: %d", err);
//NSLog (@"Current hardware sample rate: %1.0f", sampleRate);
BOOL isHighSampleRate = (sampleRate > 16000);
int bufferByteSize;
AudioQueueBufferRef buffer;
// Set up stream format fields
AudioStreamBasicDescription streamFormat;
streamFormat.mSampleRate = sampleRate;
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
streamFormat.mBitsPerChannel = 16;
streamFormat.mChannelsPerFrame = 1;
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mFramesPerPacket = 1;
streamFormat.mReserved = 0;
// New output queue ---- PLAYBACK ----
if (isPlaying == NO) {
err = AudioQueueNewOutput (&streamFormat, AudioEngineOutputBufferCallback, self, nil, nil, 0, &outputQueue);
if (err != noErr) NSLog(@"AudioQueueNewOutput() error: %d", err);
// Enqueue buffers
//outputFrequency = 0.0;
outputBuffersToRewrite = 3;
bufferByteSize = (sampleRate > 16000)? 2176 : 512; // 40.5 Hz : 31.25 Hz
for (i=0; i<3; i++) {
err = AudioQueueAllocateBuffer (outputQueue, bufferByteSize, &buffer);
if (err == noErr) {
[self generateTone: buffer];
err = AudioQueueEnqueueBuffer (outputQueue, buffer, 0, nil);
if (err != noErr) NSLog(@"AudioQueueEnqueueBuffer() error: %d", err);
} else {
NSLog(@"AudioQueueAllocateBuffer() error: %d", err);
return;
}
}
// Start playback
isPlaying = YES;
err = AudioQueueStart(outputQueue, nil);
if (err != noErr) { NSLog(@"AudioQueueStart() error: %d", err); isPlaying= NO; return; }
} else {
NSLog (@"Error: audio is already playing back.");
}
下面是產生音部分:
// AudioQueue output queue callback.
void AudioEngineOutputBufferCallback (void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
AudioEngine *engine = (AudioEngine*) inUserData;
[engine processOutputBuffer:inBuffer queue:inAQ];
}
- (void) processOutputBuffer: (AudioQueueBufferRef) buffer queue:(AudioQueueRef) queue {
OSStatus err;
if (isPlaying == YES) {
[outputLock lock];
if (outputBuffersToRewrite > 0) {
outputBuffersToRewrite--;
[self generateTone:buffer];
}
err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
if (err == 560030580) { // Queue is not active due to Music being started or other reasons
isPlaying = NO;
} else if (err != noErr) {
NSLog(@"AudioQueueEnqueueBuffer() error %d", err);
}
[outputLock unlock];
} else {
err = AudioQueueStop (queue, NO);
if (err != noErr) NSLog(@"AudioQueueStop() error: %d", err);
}
}
-(void) generateTone: (AudioQueueBufferRef) buffer {
if (outputFrequency == 0.0) {
memset(buffer->mAudioData, 0, buffer->mAudioDataBytesCapacity);
buffer->mAudioDataByteSize = buffer->mAudioDataBytesCapacity;
} else {
// Make the buffer length a multiple of the wavelength for the output frequency.
int sampleCount = buffer->mAudioDataBytesCapacity/sizeof (SInt16);
double bufferLength = sampleCount;
double wavelength = sampleRate/outputFrequency;
double repetitions = floor (bufferLength/wavelength);
if (repetitions > 0.0) {
sampleCount = round (wavelength * repetitions);
}
double x, y;
double sd = 1.0/sampleRate;
double amp = 0.9;
double max16bit = SHRT_MAX;
int i;
SInt16 *p = buffer->mAudioData;
for (i = 0; i < sampleCount; i++) {
x = i * sd * outputFrequency;
switch (outputWaveform) {
case kSine:
y = sin (x * 2.0 * M_PI);
break;
case kTriangle:
x = fmod (x, 1.0);
if (x < 0.25)
y = x * 4.0; // up 0.0 to 1.0
else if (x < 0.75)
y = (1.0 - x) * 4.0 - 2.0; // down 1.0 to -1.0
else
y = (x - 1.0) * 4.0; // up -1.0 to 0.0
break;
case kSawtooth:
y = 0.8 - fmod (x, 1.0) * 1.8;
break;
case kSquare:
y = (fmod(x, 1.0) < 0.5)? 0.7: -0.7;
break;
default: y = 0; break;
}
p[i] = y * max16bit * amp;
}
buffer->mAudioDataByteSize = sampleCount * sizeof (SInt16);
}
}
事情需要提防的是,你的回調將被調用在非主線程上,所以您必須通過鎖,互斥鎖或其他技術來練習線程安全。
高級別:使用AVAudioPlayer https://github.com/hollance/AVBufferPlayer
醫學水平:音頻序列trailsinthesand.com/exploring-iphone-audio-part-1/讓你去很好。注:我刪除了http,以便舊鏈接可以在那裏,但它確實指向了一個不好的網站,所以它顯然已經改變。
低電平:另外,您也可以下拉的水平,並與音頻單元做到這一點:http://cocoawithlove.com/2010/10/ios-tone-generator-introduction-to.html
Synth中的音頻隊列:https://github.com/hollance/AudioBufferPlayer – 2011-04-11 13:01:32
你的例子幫了我很多,再次感謝 – Amitg2k12 2011-05-14 14:53:56
這是使用相同的樣品的C#版本從@lucius
void SetupAudio()
{
AudioSession.Initialize();
AudioSession.Category = AudioSessionCategory.MediaPlayback;
sampleRate = AudioSession.CurrentHardwareSampleRate;
var format = new AudioStreamBasicDescription() {
SampleRate = sampleRate,
Format = AudioFormatType.LinearPCM,
FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger | AudioFormatFlags.LinearPCMIsPacked,
BitsPerChannel = 16,
ChannelsPerFrame = 1,
BytesPerFrame = 2,
BytesPerPacket = 2,
FramesPerPacket = 1,
};
var queue = new OutputAudioQueue (format);
var bufferByteSize = (sampleRate > 16000)? 2176 : 512; // 40.5 Hz : 31.25 Hz
var buffers = new AudioQueueBuffer* [numBuffers];
for (int i = 0; i < numBuffers; i++){
queue.AllocateBuffer (bufferByteSize, out buffers [i]);
GenerateTone (buffers [i]);
queue.EnqueueBuffer (buffers [i], null);
}
queue.OutputCompleted += (object sender, OutputCompletedEventArgs e) => {
queue.EnqueueBuffer (e.UnsafeBuffer, null);
};
queue.Start();
return true;
}
這是音調發生器:
void GenerateTone (AudioQueueBuffer *buffer)
{
// Make the buffer length a multiple of the wavelength for the output frequency.
uint sampleCount = buffer->AudioDataBytesCapacity/2;
double bufferLength = sampleCount;
double wavelength = sampleRate/outputFrequency;
double repetitions = Math.Floor (bufferLength/wavelength);
if (repetitions > 0)
sampleCount = (uint)Math.Round (wavelength * repetitions);
double x, y;
double sd = 1.0/sampleRate;
double amp = 0.9;
double max16bit = Int16.MaxValue;
int i;
short *p = (short *) buffer->AudioData;
for (i = 0; i < sampleCount; i++) {
x = i * sd * outputFrequency;
switch (outputWaveForm) {
case WaveForm.Sine:
y = Math.Sin (x * 2.0 * Math.PI);
break;
case WaveForm.Triangle:
x = x % 1.0;
if (x < 0.25)
y = x * 4.0; // up 0.0 to 1.0
else if (x < 0.75)
y = (1.0 - x) * 4.0 - 2.0; // down 1.0 to -1.0
else
y = (x - 1.0) * 4.0; // up -1.0 to 0.0
break;
case WaveForm.Sawtooth:
y = 0.8 - (x % 1.0) * 1.8;
break;
case WaveForm.Square:
y = ((x % 1.0) < 0.5)? 0.7: -0.7;
break;
default: y = 0; break;
}
p[i] = (short)(y * max16bit * amp);
}
buffer->AudioDataByteSize = sampleCount * 2;
}
}
您還希望這些定義:
enum WaveForm {
Sine, Triangle, Sawtooth, Square
}
WaveForm outputWaveForm;
const float outputFrequency = 220;
- 1. 使用音頻隊列服務記錄到數據的音頻
- 2. 音頻隊列服務 - 錄製
- 3. 將音頻與音頻隊列服務同步的建議?
- 4. 如何忽略背景音頻錄製時(使用音頻隊列服務)
- 5. 如何分析iOS中音頻隊列服務中記錄的音頻文件?
- 6. 是否可以從音頻隊列服務訪問解碼的音頻數據?
- 7. 使用音頻隊列或音頻單元的VoIP功能
- 8. 「音頻隊列服務」很好的指南?
- 9. 爲Mac音頻隊列服務選擇輸入麥克風?
- 10. iPhone上的音頻隊列服務僅播放第一個入隊緩衝區?
- 11. 如何使用音頻隊列服務播放下一個文件
- 12. 音頻隊列和EXC_BAD_ACCESS
- 13. 如何將iPod庫資源連接到音頻隊列服務並使用音頻單元進行處理?
- 14. 如何在使用音頻隊列服務時減慢或加快音頻播放?
- 15. Swift中的音頻隊列服務播放器不調用回調
- 16. 音頻使用iOS中的音頻隊列/緩衝區流式傳輸AVFoundation
- 17. 使用服務流式傳輸音頻
- 18. 使用Swift在AV錄音機中實現隊列服務
- 19. 使用示例服務
- 20. iOS 5上的音頻輸出隊列
- 21. GAE Python拉任務隊列示例
- 22. Android音頻示例項目
- 23. 此隊列屬性(iOS音頻隊列)的含義是什麼?
- 24. 音頻隊列接口可以處理40ms音頻幀嗎?
- 25. 播放流後音頻隊列無法錄製音頻
- 26. 使用iPhone中的音頻隊列錄製和播放
- 27. 使用音頻隊列的iPhone節拍器
- 28. 在iPhone應用程序中使用兩個音頻隊列
- 29. netty音頻流服務器
- 30. systemd服務音頻輸出
你能分享你的代碼嗎? – 2017-06-05 11:20:56