def parse_aiff_header(file)
chunk_size = file.read(4).unpack('N').first
type_id = file.read(4).unpack('N').first
raise unless [IFF_ID_AIFF, IFF_ID_AIFC].any? { |x| type_id == x }
sub_size = 0
sample_type = nil
sample_size = nil
num_channels = nil
block_size = nil
sample_rate = nil
is_aiff = false
while chunk_size > 0
type = file.read(4).unpack('N').first
chunk_size -= 4
case type
when IFF_ID_COMM
sub_size = file.read(4).unpack('N').first
chunk_size -= 4
num_channels = file.read(2).unpack('n').first
sub_size -= 2
num_sample_frames = file.read(4).unpack('N').first
sub_size -= 4
sample_size = file.read(2).unpack('n').first
sub_size -= 2
sample_rate = unpack_ieee(file.read(10))
sub_size -= 10
if type_id == IFF_ID_AIFC
data_type = file.read(4).unpack('N').first
sub_size -=4
raise unless [ IFF_ID_2CLE,
IFF_ID_2CBE,
IFF_ID_NONE,
].any? { |x| data_type == x }
end
file.read(sub_size)
when IFF_ID_SSND
sub_size = file.read(4).unpack('N').first
chunk_size -= sub_size
block_offset = file.read(4).unpack('N').first
sub_size -= 4
block_size = file.read(4).unpack('N').first
sub_size -= 4
sample_type = IFF_ID_SSND
file.read(block_offset)
is_aiff = true
break
else
sub_size = file.read(4).unpack('N').first
chunk_size -= sub_size
file.read(sub_size)
end
end
if is_aiff
raise "Sound data is not PCM" unless sample_type == IFF_ID_SSND
raise "Sound data is not 16 bits" unless sample_size == 16
unless num_channels == 1 || num_channels == 2
raise "Sound data is not mono or stereo"
end
raise "Block size is not 0 bytes" unless block_size == 0
end
{
:num_channels => num_channels,
:in_samplerate => simple_rate.to_i,
:num_samples => num_sample_frames,
:bit_width => sample_size,
}
end