/* * CoreAudio for 9front drawterm * kern/devaudio-core.c * link with -framework AudioToolbox * Copyright Space Aliens */ #include #undef nil #include "u.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "error.h" #include "devaudio.h" enum { Rate = 44100, Channels = 2, Bits = 16, Buffers = 4, BufferSize = 4096 * 5, PacketSize = 4, }; static int isopen = 0; static AudioStreamBasicDescription asbd; static AudioQueueRef queue; static AudioQueueBufferRef buffers[Buffers]; static uchar *rbuf = nil; static ulong rbuflen = 0; static int speed = Rate; static int bufsz = BufferSize; static void audiodevcallback(void *unused, AudioQueueRef queue, AudioQueueBufferRef buffer) { int n = bufsz; if(n > rbuflen) n = rbuflen; memcpy(buffer->mAudioData, rbuf, n); memset(&buffer->mAudioData[n], 0, bufsz - n); memmove(rbuf, rbuf + n, rbuflen - n); rbuflen -= n; buffer->mAudioDataByteSize = bufsz; AudioQueueEnqueueBuffer(queue, buffer, 0, nil); } static void audiodevinit() { int i; AudioQueueNewOutput(&asbd, audiodevcallback, nil, nil, nil, 0, &queue); for(i = 0; i < Buffers; i++){ AudioQueueAllocateBuffer(queue, bufsz, &buffers[i]); buffers[i]->mAudioDataByteSize = bufsz; memset(buffers[i]->mAudioData, 0, bufsz); AudioQueueEnqueueBuffer(queue, buffers[i], 0, nil); } AudioQueueStart(queue, nil); } void audiodevopen(void) { if(isopen != 0) oserror(); isopen = 1; asbd.mBitsPerChannel = Bits; asbd.mBytesPerFrame = Channels * (Bits/8); asbd.mFramesPerPacket = 1; asbd.mBytesPerPacket = PacketSize; asbd.mChannelsPerFrame = Channels; asbd.mFormatID = kAudioFormatLinearPCM; asbd.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; asbd.mSampleRate = speed; audiodevinit(); } void audiodevclose(void) { while(rbuflen != 0) usleep(5); AudioQueueFlush(queue); AudioQueueStop(queue, 0); AudioQueueDispose(queue, 0); if(rbuf != nil){ free(rbuf); rbuf = nil; } rbuflen = 0; isopen = 0; } int audiodevread(void *a, int n) { error("no reading"); return -1; } int audiodevwrite(void *a, int n) { double tot; rbuf = realloc(rbuf, rbuflen + n); memcpy(rbuf + rbuflen, a, n); rbuflen += n; if (rbuflen > (bufsz*(Buffers/2))) { tot = (double)n/(speed*(Bits/8)*Channels); tot *= 1000; osmsleep((int)tot); } return n; } void audiodevsetvol(int what, int left, int right) { int i; if(what == Vspeed){ speed = left; asbd.mSampleRate = speed; for(i = 1; ((i+1)*4096)<(speed/2); i++); bufsz = i * 4096; if(isopen){ AudioQueueFlush(queue); AudioQueueStop(queue, 0); AudioQueueDispose(queue, 0); audiodevinit(); } } } void audiodevgetvol(int what, int *left, int *right) { if(what == Vspeed){ *left = *right = speed; return; } *left = *right = 100; }