@@ -956,12 +956,11 @@ def wr_dat_files(self, expanded=False, write_dir=""):
956
956
dat_offsets [fn ],
957
957
True ,
958
958
[self .e_d_signal [ch ] for ch in dat_channels [fn ]],
959
- self .samps_per_frame ,
959
+ [ self .samps_per_frame [ ch ] for ch in dat_channels [ fn ]] ,
960
960
write_dir = write_dir ,
961
961
)
962
962
else :
963
- # Create a copy to prevent overwrite
964
- dsig = self .d_signal .copy ()
963
+ dsig = self .d_signal
965
964
for fn in file_names :
966
965
wr_dat_file (
967
966
fn ,
@@ -2273,16 +2272,15 @@ def wr_dat_file(
2273
2272
fmt : str
2274
2273
WFDB fmt of the dat file.
2275
2274
d_signal : ndarray
2276
- The digital conversion of the signal. Either a 2d numpy
2277
- array or a list of 1d numpy arrays.
2275
+ The digital conversion of the signal, as a 2d numpy array.
2278
2276
byte_offset : int
2279
2277
The byte offset of the dat file.
2280
2278
expanded : bool, optional
2281
2279
Whether to transform the `e_d_signal` attribute (True) or
2282
2280
the `d_signal` attribute (False).
2283
- d_signal : ndarray, optional
2284
- The expanded digital conversion of the signal. Either a 2d numpy
2285
- array or a list of 1d numpy arrays.
2281
+ e_d_signal : ndarray, optional
2282
+ The expanded digital conversion of the signal, as a list of 1d
2283
+ numpy arrays.
2286
2284
samps_per_frame : list, optional
2287
2285
The samples/frame for each signal of the dat file.
2288
2286
write_dir : str, optional
@@ -2293,10 +2291,19 @@ def wr_dat_file(
2293
2291
N/A
2294
2292
2295
2293
"""
2294
+ file_path = os .path .join (write_dir , file_name )
2295
+
2296
2296
# Combine list of arrays into single array
2297
2297
if expanded :
2298
2298
n_sig = len (e_d_signal )
2299
- sig_len = int (len (e_d_signal [0 ]) / samps_per_frame [0 ])
2299
+ if len (samps_per_frame ) != n_sig :
2300
+ raise ValueError ("mismatch between samps_per_frame and e_d_signal" )
2301
+
2302
+ sig_len = len (e_d_signal [0 ]) // samps_per_frame [0 ]
2303
+ for sig , spf in zip (e_d_signal , samps_per_frame ):
2304
+ if len (sig ) != sig_len * spf :
2305
+ raise ValueError ("mismatch in lengths of expanded signals" )
2306
+
2300
2307
# Effectively create MxN signal, with extra frame samples acting
2301
2308
# like extra channels
2302
2309
d_signal = np .zeros ((sig_len , sum (samps_per_frame )), dtype = "int64" )
@@ -2307,10 +2314,17 @@ def wr_dat_file(
2307
2314
for framenum in range (spf ):
2308
2315
d_signal [:, expand_ch ] = e_d_signal [ch ][framenum ::spf ]
2309
2316
expand_ch = expand_ch + 1
2317
+ else :
2318
+ # Create a copy to prevent overwrite
2319
+ d_signal = d_signal .copy ()
2310
2320
2311
- # This n_sig is used for making list items.
2312
- # Does not necessarily represent number of signals (ie. for expanded=True)
2313
- n_sig = d_signal .shape [1 ]
2321
+ # Non-expanded format always has 1 sample per frame
2322
+ n_sig = d_signal .shape [1 ]
2323
+ samps_per_frame = [1 ] * n_sig
2324
+
2325
+ # Total number of samples per frame (equal to number of signals if
2326
+ # expanded=False, but may be greater for expanded=True)
2327
+ tsamps_per_frame = d_signal .shape [1 ]
2314
2328
2315
2329
if fmt == "80" :
2316
2330
# convert to 8 bit offset binary form
@@ -2368,8 +2382,8 @@ def wr_dat_file(
2368
2382
# convert to 16 bit two's complement
2369
2383
d_signal [d_signal < 0 ] = d_signal [d_signal < 0 ] + 65536
2370
2384
# Split samples into separate bytes using binary masks
2371
- b1 = d_signal & [255 ] * n_sig
2372
- b2 = (d_signal & [65280 ] * n_sig ) >> 8
2385
+ b1 = d_signal & [255 ] * tsamps_per_frame
2386
+ b2 = (d_signal & [65280 ] * tsamps_per_frame ) >> 8
2373
2387
# Interweave the bytes so that the same samples' bytes are consecutive
2374
2388
b1 = b1 .reshape ((- 1 , 1 ))
2375
2389
b2 = b2 .reshape ((- 1 , 1 ))
@@ -2381,9 +2395,9 @@ def wr_dat_file(
2381
2395
# convert to 24 bit two's complement
2382
2396
d_signal [d_signal < 0 ] = d_signal [d_signal < 0 ] + 16777216
2383
2397
# Split samples into separate bytes using binary masks
2384
- b1 = d_signal & [255 ] * n_sig
2385
- b2 = (d_signal & [65280 ] * n_sig ) >> 8
2386
- b3 = (d_signal & [16711680 ] * n_sig ) >> 16
2398
+ b1 = d_signal & [255 ] * tsamps_per_frame
2399
+ b2 = (d_signal & [65280 ] * tsamps_per_frame ) >> 8
2400
+ b3 = (d_signal & [16711680 ] * tsamps_per_frame ) >> 16
2387
2401
# Interweave the bytes so that the same samples' bytes are consecutive
2388
2402
b1 = b1 .reshape ((- 1 , 1 ))
2389
2403
b2 = b2 .reshape ((- 1 , 1 ))
@@ -2397,10 +2411,10 @@ def wr_dat_file(
2397
2411
# convert to 32 bit two's complement
2398
2412
d_signal [d_signal < 0 ] = d_signal [d_signal < 0 ] + 4294967296
2399
2413
# Split samples into separate bytes using binary masks
2400
- b1 = d_signal & [255 ] * n_sig
2401
- b2 = (d_signal & [65280 ] * n_sig ) >> 8
2402
- b3 = (d_signal & [16711680 ] * n_sig ) >> 16
2403
- b4 = (d_signal & [4278190080 ] * n_sig ) >> 24
2414
+ b1 = d_signal & [255 ] * tsamps_per_frame
2415
+ b2 = (d_signal & [65280 ] * tsamps_per_frame ) >> 8
2416
+ b3 = (d_signal & [16711680 ] * tsamps_per_frame ) >> 16
2417
+ b4 = (d_signal & [4278190080 ] * tsamps_per_frame ) >> 24
2404
2418
# Interweave the bytes so that the same samples' bytes are consecutive
2405
2419
b1 = b1 .reshape ((- 1 , 1 ))
2406
2420
b2 = b2 .reshape ((- 1 , 1 ))
@@ -2410,9 +2424,54 @@ def wr_dat_file(
2410
2424
b_write = b_write .reshape ((1 , - 1 ))[0 ]
2411
2425
# Convert to un_signed 8 bit dtype to write
2412
2426
b_write = b_write .astype ("uint8" )
2427
+
2428
+ elif fmt in ("508" , "516" , "524" ):
2429
+ import soundfile
2430
+
2431
+ if any (spf != samps_per_frame [0 ] for spf in samps_per_frame ):
2432
+ raise ValueError (
2433
+ "All channels in a FLAC signal file must have the same "
2434
+ "sampling rate and samples per frame"
2435
+ )
2436
+ if n_sig > 8 :
2437
+ raise ValueError (
2438
+ "A single FLAC signal file cannot contain more than 8 channels"
2439
+ )
2440
+
2441
+ d_signal = d_signal .reshape (- 1 , n_sig , samps_per_frame [0 ])
2442
+ d_signal = d_signal .transpose (0 , 2 , 1 )
2443
+ d_signal = d_signal .reshape (- 1 , n_sig )
2444
+
2445
+ if fmt == "508" :
2446
+ d_signal = d_signal .astype ("int16" )
2447
+ np .left_shift (d_signal , 8 , out = d_signal )
2448
+ subtype = "PCM_S8"
2449
+ elif fmt == "516" :
2450
+ d_signal = d_signal .astype ("int16" )
2451
+ subtype = "PCM_16"
2452
+ elif fmt == "524" :
2453
+ d_signal = d_signal .astype ("int32" )
2454
+ np .left_shift (d_signal , 8 , out = d_signal )
2455
+ subtype = "PCM_24"
2456
+ else :
2457
+ raise ValueError (f"unknown format ({ fmt } )" )
2458
+
2459
+ sf = soundfile .SoundFile (
2460
+ file_path ,
2461
+ mode = "w" ,
2462
+ samplerate = 96000 ,
2463
+ channels = n_sig ,
2464
+ subtype = subtype ,
2465
+ format = "FLAC" ,
2466
+ )
2467
+ with sf :
2468
+ sf .write (d_signal )
2469
+ return
2470
+
2413
2471
else :
2414
2472
raise ValueError (
2415
- "This library currently only supports writing the following formats: 80, 16, 24, 32"
2473
+ "This library currently only supports writing the "
2474
+ "following formats: 80, 16, 24, 32, 508, 516, 524"
2416
2475
)
2417
2476
2418
2477
# Byte offset in the file
@@ -2427,7 +2486,7 @@ def wr_dat_file(
2427
2486
b_write = np .append (np .zeros (byte_offset , dtype = "uint8" ), b_write )
2428
2487
2429
2488
# Write the bytes to the file
2430
- with open (os . path . join ( write_dir , file_name ) , "wb" ) as f :
2489
+ with open (file_path , "wb" ) as f :
2431
2490
b_write .tofile (f )
2432
2491
2433
2492
0 commit comments