Question

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;
}
Was it helpful?

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;
}

OTHER TIPS

There's no predefined function that will create a short array from a byte array, but it should be fairly simple to do it with a for loop

// create a short array
short *shortData = malloc(sizeof(short)*audioLength);
for (i=0; i<bytearray.length, i++)
{
    shortData[i] = byteData[i];
}

The code is not rigorously correct (meaning I didn't compile it, just wrote it here on the fly), but it should give you an idea on how to do it.

Also be aware that saving audio data with two bytes instead of one can give very different results when playing back, but I'll assume you know how to handle with audio data for your specific purposes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top