質問

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;
}
役に立ちましたか?

解決

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

他のヒント

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top