Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
573 views
in Technique[技术] by (71.8m points)

objective c - NSURL returns Invalid Summary when merging WAV files

I'm trying to merge 2 .wav files inside of an Objective-C project. The idea is that i want it to give this output: file1 + (file2 - header). In that case the first file's header has to be changed to reflect the new size. If the first file is empty (so only the first time) i want the method to return the second file as a whole, but in the file 1 url. Right now i have:

+(NSURL *)mergeFile1:(NSURL *)file1 withFile2:(NSURL *)file2 {
    if(file1 == nil) {
        return [file2 copy];
    }

    NSData * wav1Data = [NSData dataWithContentsOfFile:[file1 absoluteString]];
    NSData * wav2Data = [NSData dataWithContentsOfFile:[file2 absoluteString]];

    int wav1DataSize = [wav1Data length] - 46;  
    int wav2DataSize = [wav2Data length] - 46;

    [NSMutableData dataWithData:[wav1Data subdataWithRange:NSMakeRange(46, wav1DataSize)]];

    if (wav1DataSize <= 0 ||  wav2DataSize <= 0) {
        return nil;
    }   

    NSMutableData * soundFileData = [NSMutableData dataWithData:[wav1Data subdataWithRange:NSMakeRange(0, 46)]];
    [soundFileData appendData:[wav1Data subdataWithRange:NSMakeRange(46, wav1DataSize)]];
    [soundFileData appendData:[wav2Data subdataWithRange:NSMakeRange(46, wav2DataSize)]];

    unsigned int totalLength = [soundFileData length];

    NSLog(@"%d", totalLength);

    [soundFileData replaceBytesInRange:NSMakeRange(4, 4) withBytes:[NSString stringWithFormat:@"%X", totalLength-8]];
    [soundFileData replaceBytesInRange:NSMakeRange(42, 4) withBytes:[NSString stringWithFormat:@"%X", totalLength]];

    [soundFileData writeToURL:file1 atomically:YES];

    return [file1 copy];
}

I call it like this:

if(soundFileURL != nil) {
        NSURL *tempURL = [WavUtils mergeFile1:finalSoundFileURL withFile2:soundFileURL];

        if(tempURL != nil) {
            NSLog(@"Wav files have been merged.");
            finalSoundFileURL = [tempURL copy];
            [soundFileURL release];
            soundFileURL = nil;
        } else {
            NSLog(@"Wav files could not be merged.");
        }
    }

The finalSoundFileURL is defined like this:

   @interface class : UIViewController
        ....
        NSURL *soundFileURL;
        NSURL *finalSoundFileURL;
        ....
    }

The problem i have right now is that the tempURL will return correctly, but when i do the finalSoundFileURL = [tempURL copy]; the finalSoundFileURL will say "Invalid Summary" while debugging. The tempURL will give the correct URL. I cannot play the wav in the url either, so something is clearly wrong.

Anyone has an idea what is going on, becouse i dont understand what is going on. Any help is appreciated!

EDIT

I made a few screenshots of what the debugger shows. As the picture below shows the tempURL is just fine: img1

The finalSoundFileURL at that exact same moment (after the temp being copied to the final one) shows this: img2

This is the big mystery for me. This leaves me to wonder, why is it invalid? It has just been Copied (so has its own memory space) and no release is called on it! Please correct me if i'm wrong on this.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your replaceBytesInRange calls looks a bit weird:

[soundFileData replaceBytesInRange:NSMakeRange(4, 4) withBytes:[NSString stringWithFormat:@"%X", totalLength-8]];
[soundFileData replaceBytesInRange:NSMakeRange(42, 4) withBytes:[NSString stringWithFormat:@"%X", totalLength]];

This will pass pointers to NSString instances to be used as new bytes.

I think you want to do something like this:

[soundFileData replaceBytesInRange:NSMakeRange(4, 4)
                         withBytes:&(UInt32){NSSwapHostIntToLittle(totalLength-8)}];
[soundFileData replaceBytesInRange:NSMakeRange(42, 4)
                         withBytes:&(UInt32){NSSwapHostIntToLittle(totalLength)}];

Now the length will the correct bytes in little endian order as the WAV format specifies. The byte swapping to little endian is probably a NOP when building for both iOS simulator and ARM but it's probably good to be explicit.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...