ffi-sndfile 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b113eec6ca95e787da990c8492074e91536d69f0d88c0f14ce54b36b48191080
4
+ data.tar.gz: dd944287fbcb0def4f3194ec136b3c4e9c007819e7e3970994bf444c7fc0b8b2
5
+ SHA512:
6
+ metadata.gz: 0fd357282d36ca986a2301099b2f1966c337c042f265e10571fc4d6bf47e4830818bbf6fc363bd45d27a65329368ab6f0edf6e538ae2f9fdb80b539bdc582025
7
+ data.tar.gz: cf60f0f27122780304cbd27e59d941ccacc7b0917459590622af232762ec7de852036cb922989bb9c1f98b5724169880610120c70f9d2ac74f04bd7fd8233151
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Initial release.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2026 Roel van Dijk
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # ffi-sndfile
2
+
3
+ Ruby FFI bindings for [libsndfile](https://libsndfile.github.io/libsndfile/), the library for reading and writing sound files: WAV, AIFF, FLAC, Ogg/Vorbis, Opus, MP3, CAF and many more.
4
+
5
+ See [CHANGELOG.md](CHANGELOG.md) for what changed.
6
+
7
+ ## Installation
8
+
9
+ ### Requirements
10
+
11
+ - Ruby 3.2 or newer
12
+ - libsndfile 1.0.28 or newer, including its development files:
13
+ - Ubuntu / Debian: `sudo apt-get install libsndfile1-dev`
14
+ - Fedora: `sudo dnf install libsndfile-devel`
15
+ - Arch Linux: `sudo pacman -S libsndfile`
16
+ - macOS (Homebrew): `brew install libsndfile`
17
+
18
+ Check your version with `pkg-config --modversion sndfile`. With libsndfile older than 1.0.28, `require "sndfile"` raises a `LoadError` that names the version it found. MP3 support (the `:mpeg` format and `bitrate_mode`) needs libsndfile 1.1.0 or newer, built with MPEG support.
19
+
20
+ ### Gem Installation
21
+
22
+ Add to your Gemfile:
23
+
24
+ ```ruby
25
+ gem "ffi-sndfile"
26
+ ```
27
+
28
+ And run:
29
+
30
+ ```bash
31
+ bundle install
32
+ ```
33
+
34
+ Then load it with `require "sndfile"` (or `require "ffi-sndfile"`; Bundler's auto-require uses that one). The library lives in the `SndFile` module.
35
+
36
+ ## Usage
37
+
38
+ ### Reading a Sound File
39
+
40
+ `SndFile.open` (the same as `SndFile::SoundFile.open`) opens a file. With a block, it closes the file afterwards (also when the block raises) and returns the block's value:
41
+
42
+ ```ruby
43
+ require "sndfile"
44
+
45
+ SndFile.open("song.flac") do |file|
46
+ file.samplerate # => 44100
47
+ file.channels # => 2
48
+ file.frames # => 9_261_000
49
+ file.duration # => 210.0 (seconds)
50
+ file.format # => #<SndFile::Format flac/pcm_16>
51
+
52
+ # Read in buffers of 4096 frames
53
+ file.each_buffer(4096) do |samples|
54
+ # samples is a flat Array, channels interleaved: [left, right, left, right, ...]
55
+ end
56
+ end
57
+ ```
58
+
59
+ Samples are floats from -1.0 to 1.0 by default. Pass `type:` to get another sample type; libsndfile converts between it and the file's encoding:
60
+
61
+ | `type:` | Values |
62
+ |---|---|
63
+ | `:float` (default) | Floats, -1.0 to 1.0 |
64
+ | `:double` | Floats, -1.0 to 1.0 |
65
+ | `:short` | 16 bit integers, -32768 to 32767 |
66
+ | `:int` | 32 bit integers |
67
+
68
+ ```ruby
69
+ SndFile.open("take.wav") do |file|
70
+ file.read(1024) # up to 1024 frames as floats ([] at the end of the file)
71
+ file.read(1024, type: :short) # the next 1024 frames as 16 bit integers
72
+ file.seek(0) # back to the first frame; also seek(n, :cur) and seek(-n, :end)
73
+ file.read # everything up to the end of the file
74
+ end
75
+ ```
76
+
77
+ Without a block, `open` returns the `SndFile::SoundFile`; call `close` when you're done. The file is also closed when it is garbage collected, but don't rely on that when writing: closing is what writes the final header.
78
+
79
+ ### Writing a Sound File
80
+
81
+ Writing needs a sample rate, a channel count and a format. The format can come from the file name's extension:
82
+
83
+ ```ruby
84
+ samples = Array.new(44_100) { |i| 0.5 * Math.sin(2 * Math::PI * 440 * i / 44_100) } # one second of A4
85
+
86
+ SndFile.open("a4.wav", :write, samplerate: 44_100, channels: 1) do |file|
87
+ file.write(samples) # => 44100 (frames written)
88
+ end
89
+ ```
90
+
91
+ Or give it with `format:` (a major format such as `:wav` or `:flac`) and optionally `subtype:` (the encoding) and `endian:`:
92
+
93
+ ```ruby
94
+ SndFile.open("a4.aiff", :write, format: :aiff, subtype: :pcm_24, samplerate: 48_000, channels: 2) do |file|
95
+ file << [0.1, -0.1] << [0.2, -0.2] # two stereo frames
96
+ end
97
+ ```
98
+
99
+ Without `subtype:`, common formats use a sensible default: `:pcm_16` for WAV, AIFF, FLAC and the like, `:vorbis` for Ogg and `:mpeg_layer_iii` for MP3. An unknown name or a combination libsndfile can't write (such as `format: :wav, subtype: :vorbis`) raises `ArgumentError`. Open a file with `:rdwr` to read and write it, for example to append.
100
+
101
+ ### Ogg/Vorbis with Vorbis Comments
102
+
103
+ String metadata (title, artist, ...) is written in the format's own way: as Vorbis comments in Ogg and FLAC files, as an INFO chunk in WAV files, and so on. Most formats need the strings, and encoder settings such as the quality, before the first audio is written, so pass them to `open` or set them first thing:
104
+
105
+ ```ruby
106
+ SndFile.open("song.ogg", :write, samplerate: 44_100, channels: 2,
107
+ strings: { title: "Heart of Gold", artist: "Neil Young" }) do |file|
108
+ file.strings.album = "Harvest"
109
+ file.strings[:date] = "1972"
110
+ file.vbr_quality = 0.6 # 0.0 (smallest file) to 1.0 (best quality)
111
+
112
+ file.write(samples)
113
+ end
114
+
115
+ SndFile.open("song.ogg") do |file|
116
+ file.format # => #<SndFile::Format ogg/vorbis>
117
+ file.strings.title # => "Heart of Gold"
118
+ file.strings.to_h # => {title: "Heart of Gold", artist: "Neil Young", date: "1972", album: "Harvest"}
119
+ end
120
+ ```
121
+
122
+ The strings are `title`, `copyright`, `software`, `artist`, `comment`, `date`, `album`, `license`, `tracknumber` (also `track_number`) and `genre`. They are read back as UTF-8. Setting a string after audio was written, or one the format doesn't support, raises `SndFile::SndFileError`.
123
+
124
+ Use `format: :ogg, subtype: :opus` (or a `.opus` file name) for Ogg/Opus.
125
+
126
+ ### Files in Memory and Other IO Objects
127
+
128
+ Instead of a path, you can pass an IO-like object, such as a `StringIO`, a `File` or a socket. libsndfile reads and writes it through `#read`, `#write`, `#seek` and `#pos`. A format is needed for writing, since there is no file name to take it from:
129
+
130
+ ```ruby
131
+ require "stringio"
132
+
133
+ io = StringIO.new(+"".b)
134
+ SndFile.open(io, :write, format: :ogg, samplerate: 44_100, channels: 1) { |file| file.write(samples) }
135
+ io.string # => "OggS\x00\x02..."
136
+
137
+ io.rewind
138
+ SndFile.open(io) { |file| file.frames } # => 44100
139
+ ```
140
+
141
+ Exceptions raised by the IO object are raised again by the `SndFile` call that caused them.
142
+
143
+ ### Other Settings
144
+
145
+ ```ruby
146
+ file.compression_level = 0.8 # FLAC, Ogg, MP3: 0.0 (fastest) to 1.0 (smallest)
147
+ file.bitrate_mode = :variable # MP3: :constant, :average or :variable
148
+ file.normalize_float = false # read and write floats unscaled (default: -1.0..1.0)
149
+ file.signal_max # the largest absolute sample value
150
+ file.update_header_now # make a file being written readable already
151
+ file.truncate(1000) # cut the file to 1000 frames
152
+ file.byterate # current bytes per second, or nil
153
+ file.log_info # libsndfile's log of opening the file
154
+ ```
155
+
156
+ Every other libsndfile command is available through `file.command`, which takes an `SFC_*` constant or its name as a symbol and passes the data on, for example a `SndFile::Native::BroadcastInfo` struct for the Broadcast WAV `bext` chunk:
157
+
158
+ ```ruby
159
+ bext = SndFile::Native::BroadcastInfo.new
160
+ bext.set_string(:description, "Field recording")
161
+
162
+ SndFile.open("field.wav", :write, samplerate: 48_000, channels: 2) do |file|
163
+ file.command(:set_broadcast_info, bext) # => 1 (SF_TRUE); before any audio is written
164
+ file.write(samples)
165
+ end
166
+ ```
167
+
168
+ ### Formats
169
+
170
+ ```ruby
171
+ SndFile::Format.new(:ogg, :vorbis).to_i # => 2097248 (SF_FORMAT_OGG | SF_FORMAT_VORBIS)
172
+ SndFile::Format.new(0x170002) # => #<SndFile::Format flac/pcm_16>
173
+ SndFile::Format.new(:flac).valid?(samplerate: 44_100, channels: 2) # => true
174
+
175
+ SndFile.major_formats.map(&:name) # => ["AIFF (Apple/SGI)", "AU (Sun/NeXT)", ...]
176
+ SndFile.subtypes.map(&:name) # => ["Signed 8 bit PCM", "Signed 16 bit PCM", ...]
177
+ SndFile.simple_formats # common combinations, each with its format, name and extension
178
+ SndFile::Formats.describe(:vorbis) # => #<data SndFile::FormatDescription format=..., name="Vorbis", extension=nil>
179
+ ```
180
+
181
+ The lists come from the loaded libsndfile, so they show what this installation supports.
182
+
183
+ ### Errors
184
+
185
+ Every libsndfile error is raised as a subclass of `SndFile::SndFileError`, so `rescue SndFile::SndFileError` catches them all. The message is libsndfile's own error text, and `#code` is libsndfile's error number.
186
+
187
+ | Class | libsndfile error |
188
+ |---|---|
189
+ | `SndFile::UnrecognisedFormatError` | `SF_ERR_UNRECOGNISED_FORMAT`: not a sound file, or a format libsndfile can't read |
190
+ | `SndFile::SystemError` | `SF_ERR_SYSTEM`: an operating system error, such as a missing file |
191
+ | `SndFile::MalformedFileError` | `SF_ERR_MALFORMED_FILE`: the file is damaged |
192
+ | `SndFile::UnsupportedEncodingError` | `SF_ERR_UNSUPPORTED_ENCODING`: an encoding libsndfile can't decode |
193
+ | `SndFile::SndFileError` | any of libsndfile's other, internal errors |
194
+ | `SndFile::ClosedFileError` | the `SoundFile` was used after it was closed |
195
+
196
+ ### libsndfile Version
197
+
198
+ `SndFile.version` describes the loaded libsndfile library:
199
+
200
+ ```ruby
201
+ SndFile.version.to_s # => "libsndfile-1.2.2"
202
+ SndFile.version.number # => "1.2.2"
203
+ SndFile.version >= "1.1.0" # => true
204
+ ```
205
+
206
+ ### Threads
207
+
208
+ libsndfile calls that read or write a file (`open`, `read`, `write`, `seek`, `close`, ...) let other Ruby threads keep running while they wait on the disk.
209
+
210
+ ### Low-level libsndfile Functions
211
+
212
+ Every function in `sndfile.h` is attached to `SndFile::Native`, an `FFI::Library`, for anything `SndFile::SoundFile` doesn't cover. Every struct is there too (`Native::Info` for `SF_INFO`, `Native::Instrument`, `Native::CartInfo`, `Native::ChunkInfo`, ...), and every constant is in `SndFile` (`SndFile::SF_FORMAT_OGG`, `SndFile::SFC_GET_LOG_INFO`, ...). Parameters for modes, string types, commands and seek origins also take symbols:
213
+
214
+ ```ruby
215
+ info = SndFile::Native::Info.new
216
+ sndfile = SndFile::Native.sf_open("take.wav", :read, info)
217
+ info[:frames] # => 1000
218
+ SndFile::Native.sf_get_string(sndfile, :title) # => "Old Man"
219
+ SndFile::Native.sf_close(sndfile) # => 0
220
+ ```
221
+
222
+ `sf_open`, `sf_open_fd` and `sf_open_virtual` return a handle that closes itself when it is garbage collected, unless you close it with `Native.sf_close` first; they raise a `SndFile::SndFileError` instead of returning `NULL`. Otherwise these functions return libsndfile's error codes instead of raising, and their API follows libsndfile rather than this gem.
223
+
224
+ ## Development
225
+
226
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for how to set up the project, run the specs and which Ruby versions changes need to support.
227
+
228
+ ## License
229
+
230
+ MIT License. See [LICENSE.txt](LICENSE.txt).
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Entry point matching the gem name, so `require "ffi-sndfile"` and
4
+ # `Bundler.require` load the library. Same as `require "sndfile"`.
5
+ require "sndfile"
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SndFile
4
+ # Methods for SoundFile that wrap libsndfile's sf_command. #command gives
5
+ # access to every SFC_* command; the other methods cover common ones.
6
+ #
7
+ # Encoder settings (#vbr_quality=, #compression_level=, #bitrate_mode=)
8
+ # must be set before the first audio data is written.
9
+ module Commands
10
+ # Runs an sf_command and returns its integer result. +command+ is an
11
+ # SFC_* constant or its symbol (e.g. :get_log_info); +data+ is a pointer
12
+ # (or FFI::Struct) of +size+ bytes, as the command expects.
13
+ def command(command, data = nil, size = data.respond_to?(:size) ? data.size : 0)
14
+ Native.sf_command(handle, command, data, size)
15
+ end
16
+
17
+ # libsndfile's log of what it did while opening the file.
18
+ def log_info
19
+ buffer = FFI::MemoryPointer.new(:char, 4096)
20
+ command(SFC_GET_LOG_INFO, buffer, buffer.size)
21
+ buffer.read_string
22
+ end
23
+
24
+ # Sets the encoding quality for variable bit rate formats such as Ogg
25
+ # Vorbis, Opus, FLAC and MP3: 0.0 (lowest) to 1.0 (highest).
26
+ def vbr_quality=(quality)
27
+ set_double(SFC_SET_VBR_ENCODING_QUALITY, quality, "VBR encoding quality")
28
+ end
29
+
30
+ # Sets the compression level for formats such as FLAC, Ogg and MP3:
31
+ # 0.0 (least compression) to 1.0 (most compression).
32
+ def compression_level=(level)
33
+ set_double(SFC_SET_COMPRESSION_LEVEL, level, "compression level")
34
+ end
35
+
36
+ # The bitrate mode (:constant, :average or :variable), for MPEG files.
37
+ # Returns nil when the format has none.
38
+ def bitrate_mode
39
+ mode = command(SFC_GET_BITRATE_MODE)
40
+ Native.enum_type(:sf_bitrate_mode)[mode] unless mode.negative?
41
+ end
42
+
43
+ def bitrate_mode=(mode)
44
+ value = FFI::MemoryPointer.new(:int)
45
+ value.write_int(Native.enum_type(:sf_bitrate_mode).to_native(mode, nil))
46
+ check_command(SFC_SET_BITRATE_MODE, value, value.size, "bitrate mode #{mode.inspect}")
47
+ end
48
+
49
+ # Whether floating point data is normalized to -1.0..1.0 when reading
50
+ # and writing (libsndfile's default is true).
51
+ def normalize_float?
52
+ command(SFC_GET_NORM_FLOAT) == SF_TRUE
53
+ end
54
+
55
+ def normalize_float=(normalize)
56
+ command(SFC_SET_NORM_FLOAT, nil, normalize ? SF_TRUE : SF_FALSE)
57
+ end
58
+
59
+ # Writes the file header now, so the file is valid while it is being
60
+ # written.
61
+ def update_header_now
62
+ command(SFC_UPDATE_HEADER_NOW)
63
+ self
64
+ end
65
+
66
+ # Truncates the file to +frames+ frames.
67
+ def truncate(frames)
68
+ value = FFI::MemoryPointer.new(:int64)
69
+ value.write_int64(frames)
70
+ return self if command(SFC_FILE_TRUNCATE, value).zero?
71
+
72
+ raise SndFileError, "Cannot truncate #{inspect} to #{frames} frames"
73
+ end
74
+
75
+ # The largest absolute sample value in the file (SFC_CALC_SIGNAL_MAX),
76
+ # or with normalized: true, as a fraction of the format's full scale.
77
+ def signal_max(normalized: false)
78
+ value = FFI::MemoryPointer.new(:double)
79
+ command(normalized ? SFC_CALC_NORM_SIGNAL_MAX : SFC_CALC_SIGNAL_MAX, value)
80
+ Error.check_sndfile(handle)
81
+ value.read_double
82
+ end
83
+
84
+ private
85
+
86
+ def set_double(command_id, number, description)
87
+ value = FFI::MemoryPointer.new(:double)
88
+ value.write_double(Float(number))
89
+ check_command(command_id, value, value.size, "#{description} #{number}")
90
+ end
91
+
92
+ # Runs a SET command that returns SF_TRUE on success.
93
+ def check_command(command_id, data, size, description)
94
+ return if command(command_id, data, size) == SF_TRUE
95
+
96
+ raise SndFileError, "Cannot set #{description} for #{format} files"
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The constants from sndfile.h, in the order of that header, with its comments.
4
+ module SndFile
5
+ # The following file types can be read and written. A file type would
6
+ # consist of a major type (ie SF_FORMAT_WAV) bitwise ORed with a minor type
7
+ # (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and SF_FORMAT_SUBMASK can be used
8
+ # to separate the major and minor file types.
9
+
10
+ # Major formats.
11
+ SF_FORMAT_WAV = 0x010000
12
+ SF_FORMAT_AIFF = 0x020000
13
+ SF_FORMAT_AU = 0x030000
14
+ SF_FORMAT_RAW = 0x040000
15
+ SF_FORMAT_PAF = 0x050000
16
+ SF_FORMAT_SVX = 0x060000
17
+ SF_FORMAT_NIST = 0x070000
18
+ SF_FORMAT_VOC = 0x080000
19
+ SF_FORMAT_IRCAM = 0x0A0000
20
+ SF_FORMAT_W64 = 0x0B0000
21
+ SF_FORMAT_MAT4 = 0x0C0000
22
+ SF_FORMAT_MAT5 = 0x0D0000
23
+ SF_FORMAT_PVF = 0x0E0000
24
+ SF_FORMAT_XI = 0x0F0000
25
+ SF_FORMAT_HTK = 0x100000
26
+ SF_FORMAT_SDS = 0x110000
27
+ SF_FORMAT_AVR = 0x120000
28
+ SF_FORMAT_WAVEX = 0x130000
29
+ SF_FORMAT_SD2 = 0x160000
30
+ SF_FORMAT_FLAC = 0x170000
31
+ SF_FORMAT_CAF = 0x180000
32
+ SF_FORMAT_WVE = 0x190000
33
+ SF_FORMAT_OGG = 0x200000
34
+ SF_FORMAT_MPC2K = 0x210000
35
+ SF_FORMAT_RF64 = 0x220000
36
+ SF_FORMAT_MPEG = 0x230000
37
+
38
+ # Subtypes from here on.
39
+ SF_FORMAT_PCM_S8 = 0x0001
40
+ SF_FORMAT_PCM_16 = 0x0002
41
+ SF_FORMAT_PCM_24 = 0x0003
42
+ SF_FORMAT_PCM_32 = 0x0004
43
+ SF_FORMAT_PCM_U8 = 0x0005
44
+ SF_FORMAT_FLOAT = 0x0006
45
+ SF_FORMAT_DOUBLE = 0x0007
46
+ SF_FORMAT_ULAW = 0x0010
47
+ SF_FORMAT_ALAW = 0x0011
48
+ SF_FORMAT_IMA_ADPCM = 0x0012
49
+ SF_FORMAT_MS_ADPCM = 0x0013
50
+ SF_FORMAT_GSM610 = 0x0020
51
+ SF_FORMAT_VOX_ADPCM = 0x0021
52
+ SF_FORMAT_NMS_ADPCM_16 = 0x0022
53
+ SF_FORMAT_NMS_ADPCM_24 = 0x0023
54
+ SF_FORMAT_NMS_ADPCM_32 = 0x0024
55
+ SF_FORMAT_G721_32 = 0x0030
56
+ SF_FORMAT_G723_24 = 0x0031
57
+ SF_FORMAT_G723_40 = 0x0032
58
+ SF_FORMAT_DWVW_12 = 0x0040
59
+ SF_FORMAT_DWVW_16 = 0x0041
60
+ SF_FORMAT_DWVW_24 = 0x0042
61
+ SF_FORMAT_DWVW_N = 0x0043
62
+ SF_FORMAT_DPCM_8 = 0x0050
63
+ SF_FORMAT_DPCM_16 = 0x0051
64
+ SF_FORMAT_VORBIS = 0x0060
65
+ SF_FORMAT_OPUS = 0x0064
66
+ SF_FORMAT_ALAC_16 = 0x0070
67
+ SF_FORMAT_ALAC_20 = 0x0071
68
+ SF_FORMAT_ALAC_24 = 0x0072
69
+ SF_FORMAT_ALAC_32 = 0x0073
70
+ SF_FORMAT_MPEG_LAYER_I = 0x0080
71
+ SF_FORMAT_MPEG_LAYER_II = 0x0081
72
+ SF_FORMAT_MPEG_LAYER_III = 0x0082
73
+
74
+ # Endian-ness options.
75
+ SF_ENDIAN_FILE = 0x00000000
76
+ SF_ENDIAN_LITTLE = 0x10000000
77
+ SF_ENDIAN_BIG = 0x20000000
78
+ SF_ENDIAN_CPU = 0x30000000
79
+
80
+ SF_FORMAT_SUBMASK = 0x0000FFFF
81
+ SF_FORMAT_TYPEMASK = 0x0FFF0000
82
+ SF_FORMAT_ENDMASK = 0x30000000
83
+
84
+ # The following are the valid command numbers for the sf_command()
85
+ # interface. The use of these commands is documented in the file
86
+ # command.html in the doc directory of the source code distribution.
87
+ SFC_GET_LIB_VERSION = 0x1000
88
+ SFC_GET_LOG_INFO = 0x1001
89
+ SFC_GET_CURRENT_SF_INFO = 0x1002
90
+ SFC_GET_NORM_DOUBLE = 0x1010
91
+ SFC_GET_NORM_FLOAT = 0x1011
92
+ SFC_SET_NORM_DOUBLE = 0x1012
93
+ SFC_SET_NORM_FLOAT = 0x1013
94
+ SFC_SET_SCALE_FLOAT_INT_READ = 0x1014
95
+ SFC_SET_SCALE_INT_FLOAT_WRITE = 0x1015
96
+ SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020
97
+ SFC_GET_SIMPLE_FORMAT = 0x1021
98
+ SFC_GET_FORMAT_INFO = 0x1028
99
+ SFC_GET_FORMAT_MAJOR_COUNT = 0x1030
100
+ SFC_GET_FORMAT_MAJOR = 0x1031
101
+ SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032
102
+ SFC_GET_FORMAT_SUBTYPE = 0x1033
103
+ SFC_CALC_SIGNAL_MAX = 0x1040
104
+ SFC_CALC_NORM_SIGNAL_MAX = 0x1041
105
+ SFC_CALC_MAX_ALL_CHANNELS = 0x1042
106
+ SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043
107
+ SFC_GET_SIGNAL_MAX = 0x1044
108
+ SFC_GET_MAX_ALL_CHANNELS = 0x1045
109
+ SFC_SET_ADD_PEAK_CHUNK = 0x1050
110
+ SFC_UPDATE_HEADER_NOW = 0x1060
111
+ SFC_SET_UPDATE_HEADER_AUTO = 0x1061
112
+ SFC_FILE_TRUNCATE = 0x1080
113
+ SFC_SET_RAW_START_OFFSET = 0x1090
114
+ SFC_SET_DITHER_ON_WRITE = 0x10A0
115
+ SFC_SET_DITHER_ON_READ = 0x10A1
116
+ SFC_GET_DITHER_INFO_COUNT = 0x10A2
117
+ SFC_GET_DITHER_INFO = 0x10A3
118
+ SFC_GET_EMBED_FILE_INFO = 0x10B0
119
+ SFC_SET_CLIPPING = 0x10C0
120
+ SFC_GET_CLIPPING = 0x10C1
121
+ SFC_GET_CUE_COUNT = 0x10CD
122
+ SFC_GET_CUE = 0x10CE
123
+ SFC_SET_CUE = 0x10CF
124
+ SFC_GET_INSTRUMENT = 0x10D0
125
+ SFC_SET_INSTRUMENT = 0x10D1
126
+ SFC_GET_LOOP_INFO = 0x10E0
127
+ SFC_GET_BROADCAST_INFO = 0x10F0
128
+ SFC_SET_BROADCAST_INFO = 0x10F1
129
+ SFC_GET_CHANNEL_MAP_INFO = 0x1100
130
+ SFC_SET_CHANNEL_MAP_INFO = 0x1101
131
+ SFC_RAW_DATA_NEEDS_ENDSWAP = 0x1110
132
+ # Support for Wavex Ambisonics Format
133
+ SFC_WAVEX_SET_AMBISONIC = 0x1200
134
+ SFC_WAVEX_GET_AMBISONIC = 0x1201
135
+ # RF64 files can be set so that on-close, writable files that have less
136
+ # than 4GB of data in them are converted to RIFF/WAV, as per EBU
137
+ # recommendations.
138
+ SFC_RF64_AUTO_DOWNGRADE = 0x1210
139
+
140
+ SFC_SET_VBR_ENCODING_QUALITY = 0x1300
141
+ SFC_SET_COMPRESSION_LEVEL = 0x1301
142
+
143
+ # Ogg format commands
144
+ SFC_SET_OGG_PAGE_LATENCY_MS = 0x1302
145
+ SFC_SET_OGG_PAGE_LATENCY = 0x1303
146
+ SFC_GET_OGG_STREAM_SERIALNO = 0x1306
147
+
148
+ SFC_GET_BITRATE_MODE = 0x1304
149
+ SFC_SET_BITRATE_MODE = 0x1305
150
+
151
+ # Cart Chunk support
152
+ SFC_SET_CART_INFO = 0x1400
153
+ SFC_GET_CART_INFO = 0x1401
154
+
155
+ # Opus files original samplerate metadata
156
+ SFC_SET_ORIGINAL_SAMPLERATE = 0x1500
157
+ SFC_GET_ORIGINAL_SAMPLERATE = 0x1501
158
+
159
+ # Following commands for testing only.
160
+ SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001
161
+
162
+ # These SFC_SET_ADD_* values are deprecated and will disappear at some
163
+ # time in the future. They currently do nothing and will continue to do
164
+ # nothing.
165
+ SFC_SET_ADD_HEADER_PAD_CHUNK = 0x1051
166
+ SFC_SET_ADD_DITHER_ON_WRITE = 0x1070
167
+ SFC_SET_ADD_DITHER_ON_READ = 0x1071
168
+
169
+ # String types that can be set and read from files. Not all file types
170
+ # support this and even the file types which support one, may not support
171
+ # all string types.
172
+ SF_STR_TITLE = 0x01
173
+ SF_STR_COPYRIGHT = 0x02
174
+ SF_STR_SOFTWARE = 0x03
175
+ SF_STR_ARTIST = 0x04
176
+ SF_STR_COMMENT = 0x05
177
+ SF_STR_DATE = 0x06
178
+ SF_STR_ALBUM = 0x07
179
+ SF_STR_LICENSE = 0x08
180
+ SF_STR_TRACKNUMBER = 0x09
181
+ SF_STR_GENRE = 0x10
182
+
183
+ # Use the following as the start and end index when doing metadata
184
+ # transcoding.
185
+ SF_STR_FIRST = SF_STR_TITLE
186
+ SF_STR_LAST = SF_STR_GENRE
187
+
188
+ # True and false
189
+ SF_FALSE = 0
190
+ SF_TRUE = 1
191
+
192
+ # Modes for opening files.
193
+ SFM_READ = 0x10
194
+ SFM_WRITE = 0x20
195
+ SFM_RDWR = 0x30
196
+
197
+ SF_AMBISONIC_NONE = 0x40
198
+ SF_AMBISONIC_B_FORMAT = 0x41
199
+
200
+ # Public error values. These are guaranteed to remain unchanged for the
201
+ # duration of the library major version number.
202
+ SF_ERR_NO_ERROR = 0
203
+ SF_ERR_UNRECOGNISED_FORMAT = 1
204
+ SF_ERR_SYSTEM = 2
205
+ SF_ERR_MALFORMED_FILE = 3
206
+ SF_ERR_UNSUPPORTED_ENCODING = 4
207
+
208
+ # Channel map values (used with SFC_SET/GET_CHANNEL_MAP).
209
+ SF_CHANNEL_MAP_INVALID = 0
210
+ SF_CHANNEL_MAP_MONO = 1
211
+ SF_CHANNEL_MAP_LEFT = 2
212
+ SF_CHANNEL_MAP_RIGHT = 3
213
+ SF_CHANNEL_MAP_CENTER = 4
214
+ SF_CHANNEL_MAP_FRONT_LEFT = 5
215
+ SF_CHANNEL_MAP_FRONT_RIGHT = 6
216
+ SF_CHANNEL_MAP_FRONT_CENTER = 7
217
+ SF_CHANNEL_MAP_REAR_CENTER = 8
218
+ SF_CHANNEL_MAP_REAR_LEFT = 9
219
+ SF_CHANNEL_MAP_REAR_RIGHT = 10
220
+ SF_CHANNEL_MAP_LFE = 11
221
+ SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER = 12
222
+ SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER = 13
223
+ SF_CHANNEL_MAP_SIDE_LEFT = 14
224
+ SF_CHANNEL_MAP_SIDE_RIGHT = 15
225
+ SF_CHANNEL_MAP_TOP_CENTER = 16
226
+ SF_CHANNEL_MAP_TOP_FRONT_LEFT = 17
227
+ SF_CHANNEL_MAP_TOP_FRONT_RIGHT = 18
228
+ SF_CHANNEL_MAP_TOP_FRONT_CENTER = 19
229
+ SF_CHANNEL_MAP_TOP_REAR_LEFT = 20
230
+ SF_CHANNEL_MAP_TOP_REAR_RIGHT = 21
231
+ SF_CHANNEL_MAP_TOP_REAR_CENTER = 22
232
+ SF_CHANNEL_MAP_AMBISONIC_B_W = 23
233
+ SF_CHANNEL_MAP_AMBISONIC_B_X = 24
234
+ SF_CHANNEL_MAP_AMBISONIC_B_Y = 25
235
+ SF_CHANNEL_MAP_AMBISONIC_B_Z = 26
236
+ SF_CHANNEL_MAP_MAX = 27
237
+
238
+ # Bitrate mode values (for use with SFC_GET/SET_BITRATE_MODE)
239
+ SF_BITRATE_MODE_CONSTANT = 0
240
+ SF_BITRATE_MODE_AVERAGE = 1
241
+ SF_BITRATE_MODE_VARIABLE = 2
242
+
243
+ # Enums and typedefs for adding dither on read and write.
244
+ # Reserved for future implementation.
245
+ SFD_DEFAULT_LEVEL = 0
246
+ SFD_CUSTOM_LEVEL = 0x40000000
247
+ SFD_NO_DITHER = 500
248
+ SFD_WHITE = 501
249
+ SFD_TRIANGULAR_PDF = 502
250
+
251
+ # The loop mode field in SF_INSTRUMENT will be one of the following.
252
+ SF_LOOP_NONE = 800
253
+ SF_LOOP_FORWARD = 801
254
+ SF_LOOP_BACKWARD = 802
255
+ SF_LOOP_ALTERNATING = 803
256
+
257
+ # sf_seek () uses the same values for whence (SEEK_SET, SEEK_CUR and
258
+ # SEEK_END) as stdio.h function fseek ().
259
+ SF_SEEK_SET = 0
260
+ SF_SEEK_CUR = 1
261
+ SF_SEEK_END = 2
262
+
263
+ SF_COUNT_MAX = (2**63) - 1
264
+ end