

Category: Engineering
Author: Chris Adamson, Kevin Avila
All Stack Overflow 15
This Year Stack Overflow 5
This Month Stack Overflow 4


by holy_city   2019-09-09
I was a huge fan of your app! We used to play around with it a bit in high school.

To be fair to Apple here (and this was way before my time, so I'm probably mixing stuff up) - Garageband dates to 2004 with the eMagic acquisition and was (iirc) built on top of the Logic Pro audio engine. And back then, you still had to deal with the raw CoreAudio API (if anyone wants an adventure, try finding the documentation for it... you'll have to generate it yourself!) on MacOS. I recently had to dig through the old CoreAudio mailing list and read a book [1] on the API for low latency stuff, and I'm guessing that in terms of their engine there wasn't much needing change (at least architecturally) to port to iOS. I seem to recall the biggest difference between desktop/mobile versions was the featureset and UI, I think the problem you mention was present even in Logic. You had to get hacky with ES24's key/velocity maps to do what you mention.

From working in the pro audio world for awhile, I've found that other folks in the space just love to talk shop about how they do things. Audio devs are nerds like that. Doesn't always mean people are stealing from others.

[1] https://www.amazon.com/Learning-Core-Audio-Hands-Programming...

by anonymous   2019-07-21

Solution is to use ExtAudioFile()

I found it reading the most excellent Core-Audio bible

by anonymous   2019-07-21

Core Audio is the Apple way and there are lots of examples online for working with it. To apply filters you would use AudioUnits

A new audio engine called The Amazing Audio Engine has just been released built on top of CoreAudio which might be useful.

A good book is Chris Adamson's Learning Core Audio: A Hands-on Guide to Audio Programming for Mac and iOS

by anonymous   2019-07-21

I feel that this book has a good beginning overview of Audio Units (better than any Apple provides) and equips the reader with the tools to build more complicated programs.


Chapter 7 in the book has an example of adding a reverb effect. So you can use that to guide you on whatever audio effects you want to add. As for the equalizer functions, there are audio units for it, also located in Chapter 7. If none of these accomplish what you want, you can always intercept the PCM audio data in the callback and manipulate the raw data. Though that does require you to know some DSP, which is too advanced for me.

Here are some useful posts I found:



Getting started with programmatic audio

by anonymous   2017-08-20






using AQRecorder (audioqueue recorder example) in an objective c class

trying to use AVAssetWriter for ulaw audio (2)

by anonymous   2017-08-20


CMSampleBufferRef sample;
sample = [readerOutput copyNextSampleBuffer];

CMItemCount numSamples = CMSampleBufferGetNumSamples(sample);

  // handle end of audio track here


    [broadcastLock lock];

CMSampleBufferRef sample;
sample = [readerOutput copyNextSampleBuffer];

CMItemCount numSamples = CMSampleBufferGetNumSamples(sample);

    Packet *packet = [Packet packetWithType:PacketTypeEndOfSong];
    packet.sendReliably = NO;
    [self sendPacketToAllClients:packet];
    [sampleBroadcastTimer invalidate];

        Boolean isBufferDataReady = CMSampleBufferDataIsReady(sample);

        CMBlockBufferRef CMBuffer = CMSampleBufferGetDataBuffer( sample );                                                         
        AudioBufferList audioBufferList;  

                   "could not read sample data");

        const AudioStreamPacketDescription   * inPacketDescriptions;

        size_t                               packetDescriptionsSizeOut;
        size_t inNumberPackets;

                   "could not read sample packet descriptions");

        inNumberPackets = packetDescriptionsSizeOut/sizeof(AudioStreamPacketDescription);

        AudioBuffer audioBuffer = audioBufferList.mBuffers[0];


            NSLog(@"going through packets loop");
            SInt64 dataOffset = inPacketDescriptions[i].mStartOffset;
            UInt32 dataSize   = inPacketDescriptions[i].mDataByteSize;            

            size_t packetSpaceRemaining = MAX_PACKET_SIZE - packetBytesFilled - packetDescriptionsBytesFilled;
            size_t packetDescrSpaceRemaining = MAX_PACKET_DESCRIPTIONS_SIZE - packetDescriptionsBytesFilled;        

                (packetDescrSpaceRemaining < AUDIO_STREAM_PACK_DESC_SIZE))
                if (![self encapsulateAndShipPacket:packet packetDescriptions:packetDescriptions packetID:assetOnAirID])

            memcpy((char*)packet + packetBytesFilled, 

            memcpy((char*)packetDescriptions + packetDescriptionsBytesFilled, 
                   [self encapsulatePacketDescription:inPacketDescriptions[i]

            packetBytesFilled += dataSize;
            packetDescriptionsBytesFilled += AUDIO_STREAM_PACK_DESC_SIZE; 

            // if this is the last packet, then ship it
            if (i == (inNumberPackets - 1)) {          
                if (![self encapsulateAndShipPacket:packet packetDescriptions:packetDescriptions packetID:assetOnAirID])



    [broadcastLock unlock];


- (BOOL)encapsulateAndShipPacket:(void *)source
              packetDescriptions:(void *)packetDescriptions
                        packetID:(NSString *)packetID

    // package Packet

    appendInt32(headerPacket, 'SNAP', 0);    
    appendInt32(headerPacket,packetNumber, 4);    
    appendInt16(headerPacket,PacketTypeAudioBuffer, 8);   
    // we use this so that we can add int32s later
    UInt16 filler = 0x00;
    appendInt16(headerPacket,filler, 10);    
    appendInt32(headerPacket, packetBytesFilled, 12);
    appendInt32(headerPacket, packetDescriptionsBytesFilled, 16);    
    appendUTF8String(headerPacket, [packetID UTF8String], 20);

    int offset = AUDIO_BUFFER_PACKET_HEADER_SIZE;        

    offset += packetBytesFilled;



    NSError *error;    

    Packet *packet = [Packet packetWithData:completePacket];

    // reset packet 
    packetBytesFilled = 0;
    packetDescriptionsBytesFilled = 0;

    //  free(packet); free(packetDescriptions);
    return YES;


- (char *)encapsulatePacketDescription:(AudioStreamPacketDescription)inPacketDescription

    appendInt32(packetDescription, (UInt32)mStartOffset, 0);
    appendInt32(packetDescription, inPacketDescription.mVariableFramesInPacket, 4);
    appendInt32(packetDescription, inPacketDescription.mDataByteSize,8);    

    return packetDescription;

receiving data:


    Packet *packet = [Packet packetWithData:data];
    if (packet == nil)

    Player *player = [self playerWithPeerID:peerID];

    if (player != nil)
        player.receivedResponse = YES;  // this is the new bit
    } else {
        Player *player = [[Player alloc] init];
        player.peerID = peerID;
        [_players setObject:player forKey:player.peerID];

    if (self.isServer)
        [self serverReceivedPacket:packet fromPlayer:player];

        [self clientReceivedPacket:packet];







by anonymous   2017-08-20






by anonymous   2017-08-20




by anonymous   2017-08-20
