Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/scipy/io/wavfile.py: 80%

478 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-23 06:43 +0000

1""" 

2Module to read / write wav files using NumPy arrays 

3 

4Functions 

5--------- 

6`read`: Return the sample rate (in samples/sec) and data from a WAV file. 

7 

8`write`: Write a NumPy array as a WAV file. 

9 

10""" 

11import io 

12import sys 

13import numpy 

14import struct 

15import warnings 

16from enum import IntEnum 

17 

18 

19__all__ = [ 

20 'WavFileWarning', 

21 'read', 

22 'write' 

23] 

24 

25 

26class WavFileWarning(UserWarning): 

27 pass 

28 

29 

30class WAVE_FORMAT(IntEnum): 

31 """ 

32 WAVE form wFormatTag IDs 

33 

34 Complete list is in mmreg.h in Windows 10 SDK. ALAC and OPUS are the 

35 newest additions, in v10.0.14393 2016-07 

36 """ 

37 UNKNOWN = 0x0000 

38 PCM = 0x0001 

39 ADPCM = 0x0002 

40 IEEE_FLOAT = 0x0003 

41 VSELP = 0x0004 

42 IBM_CVSD = 0x0005 

43 ALAW = 0x0006 

44 MULAW = 0x0007 

45 DTS = 0x0008 

46 DRM = 0x0009 

47 WMAVOICE9 = 0x000A 

48 WMAVOICE10 = 0x000B 

49 OKI_ADPCM = 0x0010 

50 DVI_ADPCM = 0x0011 

51 IMA_ADPCM = 0x0011 # Duplicate 

52 MEDIASPACE_ADPCM = 0x0012 

53 SIERRA_ADPCM = 0x0013 

54 G723_ADPCM = 0x0014 

55 DIGISTD = 0x0015 

56 DIGIFIX = 0x0016 

57 DIALOGIC_OKI_ADPCM = 0x0017 

58 MEDIAVISION_ADPCM = 0x0018 

59 CU_CODEC = 0x0019 

60 HP_DYN_VOICE = 0x001A 

61 YAMAHA_ADPCM = 0x0020 

62 SONARC = 0x0021 

63 DSPGROUP_TRUESPEECH = 0x0022 

64 ECHOSC1 = 0x0023 

65 AUDIOFILE_AF36 = 0x0024 

66 APTX = 0x0025 

67 AUDIOFILE_AF10 = 0x0026 

68 PROSODY_1612 = 0x0027 

69 LRC = 0x0028 

70 DOLBY_AC2 = 0x0030 

71 GSM610 = 0x0031 

72 MSNAUDIO = 0x0032 

73 ANTEX_ADPCME = 0x0033 

74 CONTROL_RES_VQLPC = 0x0034 

75 DIGIREAL = 0x0035 

76 DIGIADPCM = 0x0036 

77 CONTROL_RES_CR10 = 0x0037 

78 NMS_VBXADPCM = 0x0038 

79 CS_IMAADPCM = 0x0039 

80 ECHOSC3 = 0x003A 

81 ROCKWELL_ADPCM = 0x003B 

82 ROCKWELL_DIGITALK = 0x003C 

83 XEBEC = 0x003D 

84 G721_ADPCM = 0x0040 

85 G728_CELP = 0x0041 

86 MSG723 = 0x0042 

87 INTEL_G723_1 = 0x0043 

88 INTEL_G729 = 0x0044 

89 SHARP_G726 = 0x0045 

90 MPEG = 0x0050 

91 RT24 = 0x0052 

92 PAC = 0x0053 

93 MPEGLAYER3 = 0x0055 

94 LUCENT_G723 = 0x0059 

95 CIRRUS = 0x0060 

96 ESPCM = 0x0061 

97 VOXWARE = 0x0062 

98 CANOPUS_ATRAC = 0x0063 

99 G726_ADPCM = 0x0064 

100 G722_ADPCM = 0x0065 

101 DSAT = 0x0066 

102 DSAT_DISPLAY = 0x0067 

103 VOXWARE_BYTE_ALIGNED = 0x0069 

104 VOXWARE_AC8 = 0x0070 

105 VOXWARE_AC10 = 0x0071 

106 VOXWARE_AC16 = 0x0072 

107 VOXWARE_AC20 = 0x0073 

108 VOXWARE_RT24 = 0x0074 

109 VOXWARE_RT29 = 0x0075 

110 VOXWARE_RT29HW = 0x0076 

111 VOXWARE_VR12 = 0x0077 

112 VOXWARE_VR18 = 0x0078 

113 VOXWARE_TQ40 = 0x0079 

114 VOXWARE_SC3 = 0x007A 

115 VOXWARE_SC3_1 = 0x007B 

116 SOFTSOUND = 0x0080 

117 VOXWARE_TQ60 = 0x0081 

118 MSRT24 = 0x0082 

119 G729A = 0x0083 

120 MVI_MVI2 = 0x0084 

121 DF_G726 = 0x0085 

122 DF_GSM610 = 0x0086 

123 ISIAUDIO = 0x0088 

124 ONLIVE = 0x0089 

125 MULTITUDE_FT_SX20 = 0x008A 

126 INFOCOM_ITS_G721_ADPCM = 0x008B 

127 CONVEDIA_G729 = 0x008C 

128 CONGRUENCY = 0x008D 

129 SBC24 = 0x0091 

130 DOLBY_AC3_SPDIF = 0x0092 

131 MEDIASONIC_G723 = 0x0093 

132 PROSODY_8KBPS = 0x0094 

133 ZYXEL_ADPCM = 0x0097 

134 PHILIPS_LPCBB = 0x0098 

135 PACKED = 0x0099 

136 MALDEN_PHONYTALK = 0x00A0 

137 RACAL_RECORDER_GSM = 0x00A1 

138 RACAL_RECORDER_G720_A = 0x00A2 

139 RACAL_RECORDER_G723_1 = 0x00A3 

140 RACAL_RECORDER_TETRA_ACELP = 0x00A4 

141 NEC_AAC = 0x00B0 

142 RAW_AAC1 = 0x00FF 

143 RHETOREX_ADPCM = 0x0100 

144 IRAT = 0x0101 

145 VIVO_G723 = 0x0111 

146 VIVO_SIREN = 0x0112 

147 PHILIPS_CELP = 0x0120 

148 PHILIPS_GRUNDIG = 0x0121 

149 DIGITAL_G723 = 0x0123 

150 SANYO_LD_ADPCM = 0x0125 

151 SIPROLAB_ACEPLNET = 0x0130 

152 SIPROLAB_ACELP4800 = 0x0131 

153 SIPROLAB_ACELP8V3 = 0x0132 

154 SIPROLAB_G729 = 0x0133 

155 SIPROLAB_G729A = 0x0134 

156 SIPROLAB_KELVIN = 0x0135 

157 VOICEAGE_AMR = 0x0136 

158 G726ADPCM = 0x0140 

159 DICTAPHONE_CELP68 = 0x0141 

160 DICTAPHONE_CELP54 = 0x0142 

161 QUALCOMM_PUREVOICE = 0x0150 

162 QUALCOMM_HALFRATE = 0x0151 

163 TUBGSM = 0x0155 

164 MSAUDIO1 = 0x0160 

165 WMAUDIO2 = 0x0161 

166 WMAUDIO3 = 0x0162 

167 WMAUDIO_LOSSLESS = 0x0163 

168 WMASPDIF = 0x0164 

169 UNISYS_NAP_ADPCM = 0x0170 

170 UNISYS_NAP_ULAW = 0x0171 

171 UNISYS_NAP_ALAW = 0x0172 

172 UNISYS_NAP_16K = 0x0173 

173 SYCOM_ACM_SYC008 = 0x0174 

174 SYCOM_ACM_SYC701_G726L = 0x0175 

175 SYCOM_ACM_SYC701_CELP54 = 0x0176 

176 SYCOM_ACM_SYC701_CELP68 = 0x0177 

177 KNOWLEDGE_ADVENTURE_ADPCM = 0x0178 

178 FRAUNHOFER_IIS_MPEG2_AAC = 0x0180 

179 DTS_DS = 0x0190 

180 CREATIVE_ADPCM = 0x0200 

181 CREATIVE_FASTSPEECH8 = 0x0202 

182 CREATIVE_FASTSPEECH10 = 0x0203 

183 UHER_ADPCM = 0x0210 

184 ULEAD_DV_AUDIO = 0x0215 

185 ULEAD_DV_AUDIO_1 = 0x0216 

186 QUARTERDECK = 0x0220 

187 ILINK_VC = 0x0230 

188 RAW_SPORT = 0x0240 

189 ESST_AC3 = 0x0241 

190 GENERIC_PASSTHRU = 0x0249 

191 IPI_HSX = 0x0250 

192 IPI_RPELP = 0x0251 

193 CS2 = 0x0260 

194 SONY_SCX = 0x0270 

195 SONY_SCY = 0x0271 

196 SONY_ATRAC3 = 0x0272 

197 SONY_SPC = 0x0273 

198 TELUM_AUDIO = 0x0280 

199 TELUM_IA_AUDIO = 0x0281 

200 NORCOM_VOICE_SYSTEMS_ADPCM = 0x0285 

201 FM_TOWNS_SND = 0x0300 

202 MICRONAS = 0x0350 

203 MICRONAS_CELP833 = 0x0351 

204 BTV_DIGITAL = 0x0400 

205 INTEL_MUSIC_CODER = 0x0401 

206 INDEO_AUDIO = 0x0402 

207 QDESIGN_MUSIC = 0x0450 

208 ON2_VP7_AUDIO = 0x0500 

209 ON2_VP6_AUDIO = 0x0501 

210 VME_VMPCM = 0x0680 

211 TPC = 0x0681 

212 LIGHTWAVE_LOSSLESS = 0x08AE 

213 OLIGSM = 0x1000 

214 OLIADPCM = 0x1001 

215 OLICELP = 0x1002 

216 OLISBC = 0x1003 

217 OLIOPR = 0x1004 

218 LH_CODEC = 0x1100 

219 LH_CODEC_CELP = 0x1101 

220 LH_CODEC_SBC8 = 0x1102 

221 LH_CODEC_SBC12 = 0x1103 

222 LH_CODEC_SBC16 = 0x1104 

223 NORRIS = 0x1400 

224 ISIAUDIO_2 = 0x1401 

225 SOUNDSPACE_MUSICOMPRESS = 0x1500 

226 MPEG_ADTS_AAC = 0x1600 

227 MPEG_RAW_AAC = 0x1601 

228 MPEG_LOAS = 0x1602 

229 NOKIA_MPEG_ADTS_AAC = 0x1608 

230 NOKIA_MPEG_RAW_AAC = 0x1609 

231 VODAFONE_MPEG_ADTS_AAC = 0x160A 

232 VODAFONE_MPEG_RAW_AAC = 0x160B 

233 MPEG_HEAAC = 0x1610 

234 VOXWARE_RT24_SPEECH = 0x181C 

235 SONICFOUNDRY_LOSSLESS = 0x1971 

236 INNINGS_TELECOM_ADPCM = 0x1979 

237 LUCENT_SX8300P = 0x1C07 

238 LUCENT_SX5363S = 0x1C0C 

239 CUSEEME = 0x1F03 

240 NTCSOFT_ALF2CM_ACM = 0x1FC4 

241 DVM = 0x2000 

242 DTS2 = 0x2001 

243 MAKEAVIS = 0x3313 

244 DIVIO_MPEG4_AAC = 0x4143 

245 NOKIA_ADAPTIVE_MULTIRATE = 0x4201 

246 DIVIO_G726 = 0x4243 

247 LEAD_SPEECH = 0x434C 

248 LEAD_VORBIS = 0x564C 

249 WAVPACK_AUDIO = 0x5756 

250 OGG_VORBIS_MODE_1 = 0x674F 

251 OGG_VORBIS_MODE_2 = 0x6750 

252 OGG_VORBIS_MODE_3 = 0x6751 

253 OGG_VORBIS_MODE_1_PLUS = 0x676F 

254 OGG_VORBIS_MODE_2_PLUS = 0x6770 

255 OGG_VORBIS_MODE_3_PLUS = 0x6771 

256 ALAC = 0x6C61 

257 _3COM_NBX = 0x7000 # Can't have leading digit 

258 OPUS = 0x704F 

259 FAAD_AAC = 0x706D 

260 AMR_NB = 0x7361 

261 AMR_WB = 0x7362 

262 AMR_WP = 0x7363 

263 GSM_AMR_CBR = 0x7A21 

264 GSM_AMR_VBR_SID = 0x7A22 

265 COMVERSE_INFOSYS_G723_1 = 0xA100 

266 COMVERSE_INFOSYS_AVQSBC = 0xA101 

267 COMVERSE_INFOSYS_SBC = 0xA102 

268 SYMBOL_G729_A = 0xA103 

269 VOICEAGE_AMR_WB = 0xA104 

270 INGENIENT_G726 = 0xA105 

271 MPEG4_AAC = 0xA106 

272 ENCORE_G726 = 0xA107 

273 ZOLL_ASAO = 0xA108 

274 SPEEX_VOICE = 0xA109 

275 VIANIX_MASC = 0xA10A 

276 WM9_SPECTRUM_ANALYZER = 0xA10B 

277 WMF_SPECTRUM_ANAYZER = 0xA10C 

278 GSM_610 = 0xA10D 

279 GSM_620 = 0xA10E 

280 GSM_660 = 0xA10F 

281 GSM_690 = 0xA110 

282 GSM_ADAPTIVE_MULTIRATE_WB = 0xA111 

283 POLYCOM_G722 = 0xA112 

284 POLYCOM_G728 = 0xA113 

285 POLYCOM_G729_A = 0xA114 

286 POLYCOM_SIREN = 0xA115 

287 GLOBAL_IP_ILBC = 0xA116 

288 RADIOTIME_TIME_SHIFT_RADIO = 0xA117 

289 NICE_ACA = 0xA118 

290 NICE_ADPCM = 0xA119 

291 VOCORD_G721 = 0xA11A 

292 VOCORD_G726 = 0xA11B 

293 VOCORD_G722_1 = 0xA11C 

294 VOCORD_G728 = 0xA11D 

295 VOCORD_G729 = 0xA11E 

296 VOCORD_G729_A = 0xA11F 

297 VOCORD_G723_1 = 0xA120 

298 VOCORD_LBC = 0xA121 

299 NICE_G728 = 0xA122 

300 FRACE_TELECOM_G729 = 0xA123 

301 CODIAN = 0xA124 

302 FLAC = 0xF1AC 

303 EXTENSIBLE = 0xFFFE 

304 DEVELOPMENT = 0xFFFF 

305 

306 

307KNOWN_WAVE_FORMATS = {WAVE_FORMAT.PCM, WAVE_FORMAT.IEEE_FLOAT} 

308 

309 

310def _raise_bad_format(format_tag): 

311 try: 

312 format_name = WAVE_FORMAT(format_tag).name 

313 except ValueError: 

314 format_name = f'{format_tag:#06x}' 

315 raise ValueError(f"Unknown wave file format: {format_name}. Supported " 

316 "formats: " + 

317 ', '.join(x.name for x in KNOWN_WAVE_FORMATS)) 

318 

319 

320def _read_fmt_chunk(fid, is_big_endian): 

321 """ 

322 Returns 

323 ------- 

324 size : int 

325 size of format subchunk in bytes (minus 8 for "fmt " and itself) 

326 format_tag : int 

327 PCM, float, or compressed format 

328 channels : int 

329 number of channels 

330 fs : int 

331 sampling frequency in samples per second 

332 bytes_per_second : int 

333 overall byte rate for the file 

334 block_align : int 

335 bytes per sample, including all channels 

336 bit_depth : int 

337 bits per sample 

338 

339 Notes 

340 ----- 

341 Assumes file pointer is immediately after the 'fmt ' id 

342 """ 

343 if is_big_endian: 

344 fmt = '>' 

345 else: 

346 fmt = '<' 

347 

348 size = struct.unpack(fmt+'I', fid.read(4))[0] 

349 

350 if size < 16: 

351 raise ValueError("Binary structure of wave file is not compliant") 

352 

353 res = struct.unpack(fmt+'HHIIHH', fid.read(16)) 

354 bytes_read = 16 

355 

356 format_tag, channels, fs, bytes_per_second, block_align, bit_depth = res 

357 

358 if format_tag == WAVE_FORMAT.EXTENSIBLE and size >= (16+2): 

359 ext_chunk_size = struct.unpack(fmt+'H', fid.read(2))[0] 

360 bytes_read += 2 

361 if ext_chunk_size >= 22: 

362 extensible_chunk_data = fid.read(22) 

363 bytes_read += 22 

364 raw_guid = extensible_chunk_data[2+4:2+4+16] 

365 # GUID template {XXXXXXXX-0000-0010-8000-00AA00389B71} (RFC-2361) 

366 # MS GUID byte order: first three groups are native byte order, 

367 # rest is Big Endian 

368 if is_big_endian: 

369 tail = b'\x00\x00\x00\x10\x80\x00\x00\xAA\x00\x38\x9B\x71' 

370 else: 

371 tail = b'\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71' 

372 if raw_guid.endswith(tail): 

373 format_tag = struct.unpack(fmt+'I', raw_guid[:4])[0] 

374 else: 

375 raise ValueError("Binary structure of wave file is not compliant") 

376 

377 if format_tag not in KNOWN_WAVE_FORMATS: 

378 _raise_bad_format(format_tag) 

379 

380 # move file pointer to next chunk 

381 if size > bytes_read: 

382 fid.read(size - bytes_read) 

383 

384 # fmt should always be 16, 18 or 40, but handle it just in case 

385 _handle_pad_byte(fid, size) 

386 

387 if format_tag == WAVE_FORMAT.PCM: 

388 if bytes_per_second != fs * block_align: 

389 raise ValueError("WAV header is invalid: nAvgBytesPerSec must" 

390 " equal product of nSamplesPerSec and" 

391 " nBlockAlign, but file has nSamplesPerSec =" 

392 f" {fs}, nBlockAlign = {block_align}, and" 

393 f" nAvgBytesPerSec = {bytes_per_second}") 

394 

395 return (size, format_tag, channels, fs, bytes_per_second, block_align, 

396 bit_depth) 

397 

398 

399def _read_data_chunk(fid, format_tag, channels, bit_depth, is_big_endian, 

400 block_align, mmap=False): 

401 """ 

402 Notes 

403 ----- 

404 Assumes file pointer is immediately after the 'data' id 

405 

406 It's possible to not use all available bits in a container, or to store 

407 samples in a container bigger than necessary, so bytes_per_sample uses 

408 the actual reported container size (nBlockAlign / nChannels). Real-world 

409 examples: 

410 

411 Adobe Audition's "24-bit packed int (type 1, 20-bit)" 

412 

413 nChannels = 2, nBlockAlign = 6, wBitsPerSample = 20 

414 

415 http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Samples/AFsp/M1F1-int12-AFsp.wav 

416 is: 

417 

418 nChannels = 2, nBlockAlign = 4, wBitsPerSample = 12 

419 

420 http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/multichaudP.pdf 

421 gives an example of: 

422 

423 nChannels = 2, nBlockAlign = 8, wBitsPerSample = 20 

424 """ 

425 if is_big_endian: 

426 fmt = '>' 

427 else: 

428 fmt = '<' 

429 

430 # Size of the data subchunk in bytes 

431 size = struct.unpack(fmt+'I', fid.read(4))[0] 

432 

433 # Number of bytes per sample (sample container size) 

434 bytes_per_sample = block_align // channels 

435 n_samples = size // bytes_per_sample 

436 

437 if format_tag == WAVE_FORMAT.PCM: 

438 if 1 <= bit_depth <= 8: 

439 dtype = 'u1' # WAV of 8-bit integer or less are unsigned 

440 elif bytes_per_sample in {3, 5, 6, 7}: 

441 # No compatible dtype. Load as raw bytes for reshaping later. 

442 dtype = 'V1' 

443 elif bit_depth <= 64: 

444 # Remaining bit depths can map directly to signed numpy dtypes 

445 dtype = f'{fmt}i{bytes_per_sample}' 

446 else: 

447 raise ValueError("Unsupported bit depth: the WAV file " 

448 f"has {bit_depth}-bit integer data.") 

449 elif format_tag == WAVE_FORMAT.IEEE_FLOAT: 

450 if bit_depth in {32, 64}: 

451 dtype = f'{fmt}f{bytes_per_sample}' 

452 else: 

453 raise ValueError("Unsupported bit depth: the WAV file " 

454 f"has {bit_depth}-bit floating-point data.") 

455 else: 

456 _raise_bad_format(format_tag) 

457 

458 start = fid.tell() 

459 if not mmap: 

460 try: 

461 count = size if dtype == 'V1' else n_samples 

462 data = numpy.fromfile(fid, dtype=dtype, count=count) 

463 except io.UnsupportedOperation: # not a C-like file 

464 fid.seek(start, 0) # just in case it seeked, though it shouldn't 

465 data = numpy.frombuffer(fid.read(size), dtype=dtype) 

466 

467 if dtype == 'V1': 

468 # Rearrange raw bytes into smallest compatible numpy dtype 

469 dt = f'{fmt}i4' if bytes_per_sample == 3 else f'{fmt}i8' 

470 a = numpy.zeros((len(data) // bytes_per_sample, numpy.dtype(dt).itemsize), 

471 dtype='V1') 

472 if is_big_endian: 

473 a[:, :bytes_per_sample] = data.reshape((-1, bytes_per_sample)) 

474 else: 

475 a[:, -bytes_per_sample:] = data.reshape((-1, bytes_per_sample)) 

476 data = a.view(dt).reshape(a.shape[:-1]) 

477 else: 

478 if bytes_per_sample in {1, 2, 4, 8}: 

479 start = fid.tell() 

480 data = numpy.memmap(fid, dtype=dtype, mode='c', offset=start, 

481 shape=(n_samples,)) 

482 fid.seek(start + size) 

483 else: 

484 raise ValueError("mmap=True not compatible with " 

485 f"{bytes_per_sample}-byte container size.") 

486 

487 _handle_pad_byte(fid, size) 

488 

489 if channels > 1: 

490 data = data.reshape(-1, channels) 

491 return data 

492 

493 

494def _skip_unknown_chunk(fid, is_big_endian): 

495 if is_big_endian: 

496 fmt = '>I' 

497 else: 

498 fmt = '<I' 

499 

500 data = fid.read(4) 

501 # call unpack() and seek() only if we have really read data from file 

502 # otherwise empty read at the end of the file would trigger 

503 # unnecessary exception at unpack() call 

504 # in case data equals somehow to 0, there is no need for seek() anyway 

505 if data: 

506 size = struct.unpack(fmt, data)[0] 

507 fid.seek(size, 1) 

508 _handle_pad_byte(fid, size) 

509 

510 

511def _read_riff_chunk(fid): 

512 str1 = fid.read(4) # File signature 

513 if str1 == b'RIFF': 

514 is_big_endian = False 

515 fmt = '<I' 

516 elif str1 == b'RIFX': 

517 is_big_endian = True 

518 fmt = '>I' 

519 else: 

520 # There are also .wav files with "FFIR" or "XFIR" signatures? 

521 raise ValueError(f"File format {repr(str1)} not understood. Only " 

522 "'RIFF' and 'RIFX' supported.") 

523 

524 # Size of entire file 

525 file_size = struct.unpack(fmt, fid.read(4))[0] + 8 

526 

527 str2 = fid.read(4) 

528 if str2 != b'WAVE': 

529 raise ValueError(f"Not a WAV file. RIFF form type is {repr(str2)}.") 

530 

531 return file_size, is_big_endian 

532 

533 

534def _handle_pad_byte(fid, size): 

535 # "If the chunk size is an odd number of bytes, a pad byte with value zero 

536 # is written after ckData." So we need to seek past this after each chunk. 

537 if size % 2: 

538 fid.seek(1, 1) 

539 

540 

541def read(filename, mmap=False): 

542 """ 

543 Open a WAV file. 

544 

545 Return the sample rate (in samples/sec) and data from an LPCM WAV file. 

546 

547 Parameters 

548 ---------- 

549 filename : string or open file handle 

550 Input WAV file. 

551 mmap : bool, optional 

552 Whether to read data as memory-mapped (default: False). Not compatible 

553 with some bit depths; see Notes. Only to be used on real files. 

554 

555 .. versionadded:: 0.12.0 

556 

557 Returns 

558 ------- 

559 rate : int 

560 Sample rate of WAV file. 

561 data : numpy array 

562 Data read from WAV file. Data-type is determined from the file; 

563 see Notes. Data is 1-D for 1-channel WAV, or 2-D of shape 

564 (Nsamples, Nchannels) otherwise. If a file-like input without a 

565 C-like file descriptor (e.g., :class:`python:io.BytesIO`) is 

566 passed, this will not be writeable. 

567 

568 Notes 

569 ----- 

570 Common data types: [1]_ 

571 

572 ===================== =========== =========== ============= 

573 WAV format Min Max NumPy dtype 

574 ===================== =========== =========== ============= 

575 32-bit floating-point -1.0 +1.0 float32 

576 32-bit integer PCM -2147483648 +2147483647 int32 

577 24-bit integer PCM -2147483648 +2147483392 int32 

578 16-bit integer PCM -32768 +32767 int16 

579 8-bit integer PCM 0 255 uint8 

580 ===================== =========== =========== ============= 

581 

582 WAV files can specify arbitrary bit depth, and this function supports 

583 reading any integer PCM depth from 1 to 64 bits. Data is returned in the 

584 smallest compatible numpy int type, in left-justified format. 8-bit and 

585 lower is unsigned, while 9-bit and higher is signed. 

586 

587 For example, 24-bit data will be stored as int32, with the MSB of the 

588 24-bit data stored at the MSB of the int32, and typically the least 

589 significant byte is 0x00. (However, if a file actually contains data past 

590 its specified bit depth, those bits will be read and output, too. [2]_) 

591 

592 This bit justification and sign matches WAV's native internal format, which 

593 allows memory mapping of WAV files that use 1, 2, 4, or 8 bytes per sample 

594 (so 24-bit files cannot be memory-mapped, but 32-bit can). 

595 

596 IEEE float PCM in 32- or 64-bit format is supported, with or without mmap. 

597 Values exceeding [-1, +1] are not clipped. 

598 

599 Non-linear PCM (mu-law, A-law) is not supported. 

600 

601 References 

602 ---------- 

603 .. [1] IBM Corporation and Microsoft Corporation, "Multimedia Programming 

604 Interface and Data Specifications 1.0", section "Data Format of the 

605 Samples", August 1991 

606 http://www.tactilemedia.com/info/MCI_Control_Info.html 

607 .. [2] Adobe Systems Incorporated, "Adobe Audition 3 User Guide", section 

608 "Audio file formats: 24-bit Packed Int (type 1, 20-bit)", 2007 

609 

610 Examples 

611 -------- 

612 >>> from os.path import dirname, join as pjoin 

613 >>> from scipy.io import wavfile 

614 >>> import scipy.io 

615 

616 Get the filename for an example .wav file from the tests/data directory. 

617 

618 >>> data_dir = pjoin(dirname(scipy.io.__file__), 'tests', 'data') 

619 >>> wav_fname = pjoin(data_dir, 'test-44100Hz-2ch-32bit-float-be.wav') 

620 

621 Load the .wav file contents. 

622 

623 >>> samplerate, data = wavfile.read(wav_fname) 

624 >>> print(f"number of channels = {data.shape[1]}") 

625 number of channels = 2 

626 >>> length = data.shape[0] / samplerate 

627 >>> print(f"length = {length}s") 

628 length = 0.01s 

629 

630 Plot the waveform. 

631 

632 >>> import matplotlib.pyplot as plt 

633 >>> import numpy as np 

634 >>> time = np.linspace(0., length, data.shape[0]) 

635 >>> plt.plot(time, data[:, 0], label="Left channel") 

636 >>> plt.plot(time, data[:, 1], label="Right channel") 

637 >>> plt.legend() 

638 >>> plt.xlabel("Time [s]") 

639 >>> plt.ylabel("Amplitude") 

640 >>> plt.show() 

641 

642 """ 

643 if hasattr(filename, 'read'): 

644 fid = filename 

645 mmap = False 

646 else: 

647 fid = open(filename, 'rb') 

648 

649 try: 

650 file_size, is_big_endian = _read_riff_chunk(fid) 

651 fmt_chunk_received = False 

652 data_chunk_received = False 

653 while fid.tell() < file_size: 

654 # read the next chunk 

655 chunk_id = fid.read(4) 

656 

657 if not chunk_id: 

658 if data_chunk_received: 

659 # End of file but data successfully read 

660 warnings.warn( 

661 "Reached EOF prematurely; finished at {:d} bytes, " 

662 "expected {:d} bytes from header." 

663 .format(fid.tell(), file_size), 

664 WavFileWarning, stacklevel=2) 

665 break 

666 else: 

667 raise ValueError("Unexpected end of file.") 

668 elif len(chunk_id) < 4: 

669 msg = f"Incomplete chunk ID: {repr(chunk_id)}" 

670 # If we have the data, ignore the broken chunk 

671 if fmt_chunk_received and data_chunk_received: 

672 warnings.warn(msg + ", ignoring it.", WavFileWarning, 

673 stacklevel=2) 

674 else: 

675 raise ValueError(msg) 

676 

677 if chunk_id == b'fmt ': 

678 fmt_chunk_received = True 

679 fmt_chunk = _read_fmt_chunk(fid, is_big_endian) 

680 format_tag, channels, fs = fmt_chunk[1:4] 

681 bit_depth = fmt_chunk[6] 

682 block_align = fmt_chunk[5] 

683 elif chunk_id == b'fact': 

684 _skip_unknown_chunk(fid, is_big_endian) 

685 elif chunk_id == b'data': 

686 data_chunk_received = True 

687 if not fmt_chunk_received: 

688 raise ValueError("No fmt chunk before data") 

689 data = _read_data_chunk(fid, format_tag, channels, bit_depth, 

690 is_big_endian, block_align, mmap) 

691 elif chunk_id == b'LIST': 

692 # Someday this could be handled properly but for now skip it 

693 _skip_unknown_chunk(fid, is_big_endian) 

694 elif chunk_id in {b'JUNK', b'Fake'}: 

695 # Skip alignment chunks without warning 

696 _skip_unknown_chunk(fid, is_big_endian) 

697 else: 

698 warnings.warn("Chunk (non-data) not understood, skipping it.", 

699 WavFileWarning, stacklevel=2) 

700 _skip_unknown_chunk(fid, is_big_endian) 

701 finally: 

702 if not hasattr(filename, 'read'): 

703 fid.close() 

704 else: 

705 fid.seek(0) 

706 

707 return fs, data 

708 

709 

710def write(filename, rate, data): 

711 """ 

712 Write a NumPy array as a WAV file. 

713 

714 Parameters 

715 ---------- 

716 filename : string or open file handle 

717 Output wav file. 

718 rate : int 

719 The sample rate (in samples/sec). 

720 data : ndarray 

721 A 1-D or 2-D NumPy array of either integer or float data-type. 

722 

723 Notes 

724 ----- 

725 * Writes a simple uncompressed WAV file. 

726 * To write multiple-channels, use a 2-D array of shape 

727 (Nsamples, Nchannels). 

728 * The bits-per-sample and PCM/float will be determined by the data-type. 

729 

730 Common data types: [1]_ 

731 

732 ===================== =========== =========== ============= 

733 WAV format Min Max NumPy dtype 

734 ===================== =========== =========== ============= 

735 32-bit floating-point -1.0 +1.0 float32 

736 32-bit PCM -2147483648 +2147483647 int32 

737 16-bit PCM -32768 +32767 int16 

738 8-bit PCM 0 255 uint8 

739 ===================== =========== =========== ============= 

740 

741 Note that 8-bit PCM is unsigned. 

742 

743 References 

744 ---------- 

745 .. [1] IBM Corporation and Microsoft Corporation, "Multimedia Programming 

746 Interface and Data Specifications 1.0", section "Data Format of the 

747 Samples", August 1991 

748 http://www.tactilemedia.com/info/MCI_Control_Info.html 

749 

750 Examples 

751 -------- 

752 Create a 100Hz sine wave, sampled at 44100Hz. 

753 Write to 16-bit PCM, Mono. 

754 

755 >>> from scipy.io.wavfile import write 

756 >>> import numpy as np 

757 >>> samplerate = 44100; fs = 100 

758 >>> t = np.linspace(0., 1., samplerate) 

759 >>> amplitude = np.iinfo(np.int16).max 

760 >>> data = amplitude * np.sin(2. * np.pi * fs * t) 

761 >>> write("example.wav", samplerate, data.astype(np.int16)) 

762 

763 """ 

764 if hasattr(filename, 'write'): 

765 fid = filename 

766 else: 

767 fid = open(filename, 'wb') 

768 

769 fs = rate 

770 

771 try: 

772 dkind = data.dtype.kind 

773 if not (dkind == 'i' or dkind == 'f' or (dkind == 'u' and 

774 data.dtype.itemsize == 1)): 

775 raise ValueError("Unsupported data type '%s'" % data.dtype) 

776 

777 header_data = b'' 

778 

779 header_data += b'RIFF' 

780 header_data += b'\x00\x00\x00\x00' 

781 header_data += b'WAVE' 

782 

783 # fmt chunk 

784 header_data += b'fmt ' 

785 if dkind == 'f': 

786 format_tag = WAVE_FORMAT.IEEE_FLOAT 

787 else: 

788 format_tag = WAVE_FORMAT.PCM 

789 if data.ndim == 1: 

790 channels = 1 

791 else: 

792 channels = data.shape[1] 

793 bit_depth = data.dtype.itemsize * 8 

794 bytes_per_second = fs*(bit_depth // 8)*channels 

795 block_align = channels * (bit_depth // 8) 

796 

797 fmt_chunk_data = struct.pack('<HHIIHH', format_tag, channels, fs, 

798 bytes_per_second, block_align, bit_depth) 

799 if not (dkind == 'i' or dkind == 'u'): 

800 # add cbSize field for non-PCM files 

801 fmt_chunk_data += b'\x00\x00' 

802 

803 header_data += struct.pack('<I', len(fmt_chunk_data)) 

804 header_data += fmt_chunk_data 

805 

806 # fact chunk (non-PCM files) 

807 if not (dkind == 'i' or dkind == 'u'): 

808 header_data += b'fact' 

809 header_data += struct.pack('<II', 4, data.shape[0]) 

810 

811 # check data size (needs to be immediately before the data chunk) 

812 if ((len(header_data)-4-4) + (4+4+data.nbytes)) > 0xFFFFFFFF: 

813 raise ValueError("Data exceeds wave file size limit") 

814 

815 fid.write(header_data) 

816 

817 # data chunk 

818 fid.write(b'data') 

819 fid.write(struct.pack('<I', data.nbytes)) 

820 if data.dtype.byteorder == '>' or (data.dtype.byteorder == '=' and 

821 sys.byteorder == 'big'): 

822 data = data.byteswap() 

823 _array_tofile(fid, data) 

824 

825 # Determine file size and place it in correct 

826 # position at start of the file. 

827 size = fid.tell() 

828 fid.seek(4) 

829 fid.write(struct.pack('<I', size-8)) 

830 

831 finally: 

832 if not hasattr(filename, 'write'): 

833 fid.close() 

834 else: 

835 fid.seek(0) 

836 

837 

838def _array_tofile(fid, data): 

839 # ravel gives a c-contiguous buffer 

840 fid.write(data.ravel().view('b').data)