我正在尝试操作wave文件头。我已将文件加载到NSMutableData中,并尝试更改wav文件头信息。我的问题在于:
[maindata replaceBytesInRange:range withBytes:((UInt32 *)tfSC1Length)];
我收到了EXC_BAD_ACCESS错误。无法理解为什么。有什么想法吗?
我使用的代码如下:
// calculate total file length (minus 8 for the header), chunk size, number of channels, sample rate and bits per sample
int tfLength = ([maindata length] - 8);
int tfChannels = 1; // mono
int tfSampleRate = 44100;
int tfDataLength = ([maindata length] - 44);
int tfBitsPerSample = 16;
int tfSC1Length = 16;
int tfAudioFormat = 1;
//we are rebuilding the header for the wave files...
// chunk identifier
((char *)[maindata mutableBytes])[0] = 'R';
((char *)[maindata mutableBytes])[1] = 'I';
((char *)[maindata mutableBytes])[2] = 'F';
((char *)[maindata mutableBytes])[3] = 'F';
// size (less 8 bytes)
NSRange range;
range.location = 4;
range.length = 4;
[maindata replaceBytesInRange:range withBytes:(UInt32 *)tfLength];
// the file format
((char *)[maindata mutableBytes])[8] = 'W';
((char *)[maindata mutableBytes])[9] = 'A';
((char *)[maindata mutableBytes])[10] = 'V';
((char *)[maindata mutableBytes])[11] = 'E';
// subchunk1 ID
((char *)[maindata mutableBytes])[12] = 'f';
((char *)[maindata mutableBytes])[13] = 'm';
((char *)[maindata mutableBytes])[14] = 't';
((char *)[maindata mutableBytes])[15] = ' ';
// subchunk length
range.location = 16;
range.length = 4;
[maindata replaceBytesInRange:range withBytes:((UInt32 *)tfSC1Length)];
// audio format
range.location = 20;
range.length = 2;
[maindata replaceBytesInRange:range withBytes:((UInt16 *)tfAudioFormat)];
// number of channels
range.location = 22;
range.length = 2;
[maindata replaceBytesInRange:range withBytes:((UInt16 *)tfChannels)];
// sample rate
range.location = 24;
range.length = 4;
[maindata replaceBytesInRange:range withBytes:((UInt32 *)tfSampleRate)];
// byte rate
range.location = 28;
range.length = 4;
[maindata replaceBytesInRange:range withBytes:((UInt32 *)(tfSampleRate * ((tfBitsPerSample * tfChannels) / 8)))];
// block align
range.location = 32;
range.length = 2;
[maindata replaceBytesInRange:range withBytes:((UInt16 *)((tfBitsPerSample * tfChannels) / 8))];
// bits per sample
range.location = 34;
range.length = 2;
[maindata replaceBytesInRange:range withBytes:((UInt16 *)tfBitsPerSample)];
// adjust the length field of the wave file...
((char *)[maindata mutableBytes])[36] = 'd';
((char *)[maindata mutableBytes])[37] = 'a';
((char *)[maindata mutableBytes])[38] = 't';
((char *)[maindata mutableBytes])[39] = 'a';
// length of the audio data
range.location = 40;
range.length = 4;
[maindata replaceBytesInRange:range withBytes:(UInt32 *)tfDataLength];
答案 0 :(得分:5)
我建议使用结构来引用标题:
typedef struct {
UInt32 riffChunkID; // Always RIFF, in big endian. Integer fields are little-ending.
UInt32 fileLength;
UInt32 waveFileID; // 'WAVE' for Wave files.
UInt32 formatChunkID; // 'fmt '
UInt32 formatChunkSize;
SInt16 formatTag; // Wave Format ID: see constants
SInt16 channels; // Number of Channels: 1=mono, 2=stereo
SInt32 sampleRate; // Sample Rate: samples per second
SInt32 bytesPerSec; // sampleRate * blockAlign
SInt16 blockAlign; // sample frame size = channels * sampleSize / 8
SInt16 bitsPerSample; // sampleSize (8 or 16), also two's-complement for 16-bit, offset for 8-bit
UInt32 dataChunkID; // 'data'
UInt32 dataChunkSize;
} WaveHeader;
int tfChannels = 1; // mono
int tfSampleRate = 44100;
int tfBitsPerSample = 16;
WaveHeader *header = [maindata mutableBytes];
header->riffChunkID = CFSwapInt32HostToBig ('RIFF');
header->fileLength = CFSwapInt32HostToLittle ([maindata length] - 8);
header->waveFileID = CFSwapInt32HostToBig ('WAVE');
header->formatChunkID = CFSwapInt32HostToBig ('fmt ');
header->formatChunkSize = CFSwapInt32HostToLittle (16);
header->formatTag = CFSwapInt16HostToLittle (1);
header->channels = CFSwapInt16HostToLittle (tfChannels);
header->sampleRate = CFSwapInt32HostToLittle (tfSampleRate);
header->bytesPerSec = CFSwapInt32HostToLittle (tfSampleRate * tfBitsPerSample / 8 * tfChannels);
header->blockAlign = CFSwapInt16HostToLittle (tfBitsPerSample / 8 * tfChannels);
header->bitsPerSample = CFSwapInt16HostToLittle (tfBitsPerSample);
header->dataChunkID = CFSwapInt32HostToBig ('data');
header->dataChunkSize = CFSwapInt32HostToLittle ([maindata length] - 44);
短得多。希望这会有所帮助。
答案 1 :(得分:3)
你需要使用“&”如果要将其值复制到数据缓冲区,则运算符获取整数值的地址:
所以而不是:
[maindata replaceBytesInRange:range withBytes:(UInt32 *)tfLength];
使用:
[maindata replaceBytesInRange:range withBytes: &tfLength];
这导致你的崩溃,因为它现在把你的长度当作指针。
另外,对于16位和32位整数,wav文件格式的字节顺序是多少?它与iPhone和iPhone模拟器上的字节顺序相同吗?您可以使用CFByteOrder utilities转换为正确的字节顺序。
另外,在声明长度以确保正确复制长度时,我会使用计数的确切类型(UInt32,UInt16)而不是int。现在你实现的方式是假设UInt32与int(可能是真的)二进制相同,并且int的前2个字节与具有相同值的UInt16相同(不一定是真的)。