Search code examples
iosobjective-caudioeffectsvoice

How to transform byte array in short array with Objective-C?


I'm developing a mobile application for iOS related to voice recording.

Due to that fact, I'm developing some different sound effects to modify recorded voice but I have a problem to implement some of them.

I'm trying to create echo/delay effect and I need to transform a byte array into a short array but I have no idea how to do it in Objective-C.

Thanks.

This is my current source code to implement it, but like byte is a very short type, when I apply attenuation (what must return a float value) produce an awful noise in my audio.

- (NSURL *)echo:(NSURL *)input output:(NSURL *)output{

    int delay = 50000;
    float attenuation = 0.5f;

    NSMutableData *audioData = [NSMutableData dataWithContentsOfURL:input];
    NSUInteger dataSize = [audioData length] - 44;
    NSUInteger audioLength = [audioData length];

    NSUInteger newAudioLength = audioLength + delay;


    // Copy bytes
    Byte *byteData = (Byte*)malloc(audioLength);
    memcpy(byteData, [audioData bytes], audioLength);

    short *shortData = (short*)malloc(audioLength/2);

    // create a new array to store new modify data
    Byte *newByteData = (Byte*)malloc(newAudioLength);
    newByteData = byteData;

    for (int i = 44; i < audioLength - delay; i++)
    {
        newByteData[i + delay] += byteData[i] * attenuation;
    }

    // Copy bytes in a new NSMutableData
    NSMutableData *newAudioData = [NSMutableData dataWithBytes:newByteData length:newAudioLength];

    // Store in a file
    [newAudioData writeToFile:[output path] atomically:YES];

    // Set WAV size
    [[AudioUtils alloc] setAudioFileSize:output];

    return output;
}

Solution

  • Finally, I could finish my echo effect implementing these four methods. I hope they will be useful for you.

    Byte to short array

    - (short *) byte2short:(Byte *)bytes size:(int)size resultSize:(int)resultSize{
        short *shorts = (short *)malloc(sizeof(short)*resultSize);
        for (int i=0; i < size/2; i++){
            shorts[i] = (bytes[i*2+1] << 8) | bytes[i*2];
        }
        return shorts;
    }
    

    Short to byte array

    - (Byte *) short2byte:(short *)shorts size:(int)size resultSize:(int)resultSize{
        Byte *bytes = (Byte *)malloc(sizeof(Byte)*resultSize);
        for (int i = 0; i < size; i++)
        {
            bytes[i * 2] = (Byte) (shorts[i] & 0x00FF);
            bytes[(i * 2) + 1] = (Byte) (shorts[i] >> 8);
            shorts[i] = 0;
        }
        return bytes;
    }
    

    Effect

    - (NSMutableData *) effect:(NSMutableData *)data delay:(int)delay attenuation:(float)attenuation{
        NSUInteger audioLength = [data length];
    
        // Copy original data in a byte array
        Byte *byteData = (Byte*)malloc(sizeof(Byte)*audioLength);
        memcpy(byteData, [data bytes], audioLength);
    
        short *shortData = (short*)malloc(sizeof(short)*(audioLength/2 + delay));
        shortData = [self byte2short:byteData size:(int)audioLength resultSize:(int)audioLength/2 + delay];
    
        // Array to store shorts
        short *newShortData = shortData;
    
        for (int i = 44; i < audioLength/2; i++)
        {
            newShortData[i + delay] += (short)((float)shortData[i] * attenuation);
        }
    
        Byte *newByteData = [self short2byte:newShortData size:(int)(audioLength/2 + delay) resultSize:(int)(audioLength + delay*2)];
        // Copy bytes to a NSMutableData in order to create new file
        NSMutableData *newAudioData = [NSMutableData dataWithBytes:newByteData length:(int)(audioLength + delay*2)];
    
        return newAudioData;
    }
    

    Echo effect

    - (NSURL *)echo:(NSURL *)input output:(NSURL *)output{
    
        NSMutableData *audioData = [NSMutableData dataWithContentsOfURL:input];
    
        // we call effect method that returns a NSMutableData and create a new file
        [[self effect:audioData delay:6000 attenuation:0.5f] writeToFile:[output path] atomically:YES];
    
        // We set file's size (is a method I have implemented)
        [[AudioUtils alloc] setAudioFileSize:output];
    
        return output;
    }