File: sample_chunk_reader.rb

package info (click to toggle)
ruby-wavefile 1.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,708 kB
  • sloc: ruby: 4,171; makefile: 2
file content (74 lines) | stat: -rw-r--r-- 2,544 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
module WaveFile
  module ChunkReaders
    # Internal
    class SampleChunkReader < BaseChunkReader    # :nodoc:
      def initialize(io, chunk_size)
        @io = io
        @chunk_size = chunk_size
      end

      def read
        if @chunk_size < CORE_BYTE_COUNT
          raise_error InvalidFormatError, "The sample chunk is incomplete; it contains fewer than the required number of fields."
        end

        raw_bytes = read_entire_chunk_body(CHUNK_IDS[:sample])

        fields = {}
        fields[:manufacturer_id],
        fields[:product_id],
        fields[:sample_nanoseconds],
        fields[:midi_note],
        fields[:fine_tuning_cents],
        fields[:smpte_format],
        smpte_offset_frames,
        smpte_offset_seconds,
        smpte_offset_minutes,
        smpte_offset_hours,
        loop_count,
        sampler_data_size = raw_bytes.slice!(0...CORE_BYTE_COUNT).unpack("VVVVVVCCCcVV")
        fields[:fine_tuning_cents] = (fields[:fine_tuning_cents] / 4_294_967_296.0) * 100
        fields[:smpte_offset] = SMPTETimecode.new(hours: smpte_offset_hours,
                                                  minutes: smpte_offset_minutes,
                                                  seconds: smpte_offset_seconds,
                                                  frames: smpte_offset_frames)

        fields[:loops] = []
        loop_count.times do
          if raw_bytes.length < LOOP_BYTE_COUNT
            raise_error InvalidFormatError, "`smpl` chunk loop count is #{loop_count}, but it does not contain that many loops"
          end

          loop_fields = {}
          loop_fields[:id],
          loop_fields[:type],
          loop_fields[:start_sample_frame],
          loop_fields[:end_sample_frame],
          loop_fields[:fraction],
          loop_fields[:play_count] = raw_bytes.slice!(0...LOOP_BYTE_COUNT).unpack("VVVVVV")
          loop_fields[:type] = loop_fields[:type]
          loop_fields[:fraction] /= 4_294_967_296.0

          fields[:loops] << SamplerLoop.new(**loop_fields)
        end

        if sampler_data_size > 0
          if raw_bytes.length < sampler_data_size
            raise_error InvalidFormatError, "`smpl` chunk \"sampler specific data\" field is smaller than expected."
          end

          fields[:sampler_specific_data] = raw_bytes.slice!(0...sampler_data_size)
        else
          fields[:sampler_specific_data] = ""
        end

        SamplerInfo.new(**fields)
      end

      private

      CORE_BYTE_COUNT = 36
      LOOP_BYTE_COUNT = 24
    end
  end
end