@@ -1891,6 +1891,160 @@ def mit2edf(record_name, pn_dir=None, sampfrom=0, sampto=None, channels=None,
1891
1891
print ('WARNING: output contains an invalid character, {}, at byte {}' .format (val , i ))
1892
1892
1893
1893
1894
+ def mit2wav (record_name , pn_dir = None , sampfrom = 0 , sampto = None , channels = None ,
1895
+ output_filename = '' , write_header = False ):
1896
+ """
1897
+ This program converts a WFDB record into .wav format (format 16, multiplexed
1898
+ signals, with embedded header information). Use 'wav2mit' to perform the
1899
+ reverse conversion.
1900
+
1901
+ Parameters
1902
+ ----------
1903
+ record_name : str
1904
+ The name of the input WFDB record to be read. Can also work with both
1905
+ EDF and WAV files.
1906
+ pn_dir : str, optional
1907
+ Option used to stream data from Physionet. The Physionet
1908
+ database directory from which to find the required record files.
1909
+ eg. For record '100' in 'http://physionet.org/content/mitdb'
1910
+ pn_dir='mitdb'.
1911
+ sampfrom : int, optional
1912
+ The starting sample number to read for all channels.
1913
+ sampto : int, 'end', optional
1914
+ The sample number at which to stop reading for all channels.
1915
+ Reads the entire duration by default.
1916
+ channels : list, optional
1917
+ List of integer indices specifying the channels to be read.
1918
+ Reads all channels by default.
1919
+ output_filename : str, optional
1920
+ The desired name of the output file. If this value set to the
1921
+ default value of '', then the output filename will be 'REC.wav'.
1922
+ write_header : bool, optional
1923
+ Whether to write (True) or not to write (False) a header file to
1924
+ accompany the generated WAV file. The default value is 'False'.
1925
+
1926
+ Returns
1927
+ -------
1928
+ N/A
1929
+
1930
+ Notes
1931
+ -----
1932
+ Files that can be processed successfully using `wav2mit` always have exactly
1933
+ three chunks (a header chunk, a format chunk, and a data chunk). In .wav
1934
+ files, binary data are always written in little-endian format (least
1935
+ significant byte first). The format of `wav2mit`'s input files is as follows:
1936
+
1937
+ [Header chunk]
1938
+ Bytes 0 - 3: "RIFF" [4 ASCII characters]
1939
+ Bytes 4 - 7: L-8 (number of bytes to follow in the file, excluding bytes 0-7)
1940
+ Bytes 8 - 11: "WAVE" [4 ASCII characters]
1941
+
1942
+ [Format chunk]
1943
+ Bytes 12 - 15: "fmt " [4 ASCII characters, note trailing space]
1944
+ Bytes 16 - 19: 16 (format chunk length in bytes, excluding bytes 12-19)
1945
+ Bytes 20 - 35: format specification, consisting of:
1946
+ Bytes 20 - 21: 1 (format tag, indicating no compression is used)
1947
+ Bytes 22 - 23: number of signals (1 - 65535)
1948
+ Bytes 24 - 27: sampling frequency in Hz (per signal)
1949
+ Note that the sampling frequency in a .wav file must be an
1950
+ integer multiple of 1 Hz, a restriction that is not imposed
1951
+ by MIT (WFDB) format.
1952
+ Bytes 28 - 31: bytes per second (sampling frequency * frame size in bytes)
1953
+ Bytes 32 - 33: frame size in bytes
1954
+ Bytes 34 - 35: bits per sample (ADC resolution in bits)
1955
+ Note that the actual ADC resolution (e.g., 12) is written in
1956
+ this field, although each output sample is right-padded to fill
1957
+ a full (16-bit) word. (.wav format allows for 8, 16, 24, and
1958
+ 32 bits per sample)
1959
+
1960
+ [Data chunk]
1961
+ Bytes 36 - 39: "data" [4 ASCII characters]
1962
+ Bytes 40 - 43: L-44 (number of bytes to follow in the data chunk)
1963
+ Bytes 44 - L-1: sample data, consisting of:
1964
+ Bytes 44 - 45: sample 0, channel 0
1965
+ Bytes 46 - 47: sample 0, channel 1
1966
+ ... etc. (same order as in a multiplexed WFDB signal file)
1967
+
1968
+ Examples
1969
+ --------
1970
+ >>> wfdb.mit2wav('100', pn_dir='pwave')
1971
+
1972
+ The output file name is '100.wav'
1973
+
1974
+ """
1975
+ record = rdrecord (record_name , pn_dir = pn_dir , sampfrom = sampfrom ,
1976
+ sampto = sampto , smooth_frames = False )
1977
+ record_name_out = record_name .split (os .sep )[- 1 ].replace ('-' ,'_' )
1978
+
1979
+ # Get information needed for the header and format chunks
1980
+ num_samps = record .sig_len
1981
+ samps_per_second = record .fs
1982
+ frame_length = record .n_sig * 2
1983
+ chunk_bytes = num_samps * frame_length
1984
+ file_bytes = chunk_bytes + 36
1985
+ bits_per_sample = max (record .adc_res )
1986
+ offset = record .adc_zero
1987
+ shift = [(16 - v ) for v in record .adc_res ]
1988
+
1989
+ # Start writing the file
1990
+ if output_filename != '' :
1991
+ if not output_filename .endswith ('.wav' ):
1992
+ raise Exception ("Name of output file must end in '.wav'" )
1993
+ else :
1994
+ output_filename = record_name_out + '.wav'
1995
+
1996
+ with open (output_filename , 'wb' ) as f :
1997
+ # Write the WAV file identifier
1998
+ f .write (struct .pack ('>4s' , b'RIFF' ))
1999
+ # Write the number of bytes to follow in the file
2000
+ # (num_samps*frame_length) sample bytes, and 36 more bytes of miscellaneous embedded header
2001
+ f .write (struct .pack ('<I' , file_bytes ))
2002
+ # Descriptor for the format of the file
2003
+ f .write (struct .pack ('>8s' , b'WAVEfmt ' ))
2004
+ # Number of bytes to follow in the format chunk
2005
+ f .write (struct .pack ('<I' , 16 ))
2006
+ # The format tag
2007
+ f .write (struct .pack ('<H' , 1 ))
2008
+ # The number of signals
2009
+ f .write (struct .pack ('<H' , record .n_sig ))
2010
+ # The samples per second
2011
+ f .write (struct .pack ('<I' , samps_per_second ))
2012
+ # The number of bytes per second
2013
+ f .write (struct .pack ('<I' , samps_per_second * frame_length ))
2014
+ # The length of each frame
2015
+ f .write (struct .pack ('<H' , frame_length ))
2016
+ # The number of bits per samples
2017
+ f .write (struct .pack ('<H' , bits_per_sample ))
2018
+ # The descriptor to indicate that the data information is next
2019
+ f .write (struct .pack ('>4s' , b'data' ))
2020
+ # The number of bytes in the signal data chunk
2021
+ f .write (struct .pack ('<I' , chunk_bytes ))
2022
+ # Write the signal data... the closest I can get to the original implementation
2023
+ # Mismatched elements: 723881 / 15400000 (4.7%)
2024
+ # Max absolute difference: 2
2025
+ # Max relative difference: 0.00444444
2026
+ # x: array([ -322, 3852, -9246, ..., 0, 0, 0], dtype=int16)
2027
+ # y: array([ -322, 3852, -9246, ..., 0, 0, 0], dtype=int16)
2028
+ sig_data = np .left_shift (np .subtract (record .adc (), offset ), shift ).reshape ((1 , - 1 )).astype (np .int16 )
2029
+ sig_data .tofile (f )
2030
+
2031
+ # If asked to write the accompanying header file
2032
+ if write_header :
2033
+ record .adc_zero = record .n_sig * [0 ]
2034
+ record .adc_res = record .n_sig * [16 ]
2035
+ record .adc_gain = [(r * (1 << shift [i ])) for i ,r in enumerate (record .adc_gain )]
2036
+ record .baseline = [(b - offset [i ]) for i ,b in enumerate (record .baseline )]
2037
+ record .baseline = [(b * (1 << shift [i ])) for i ,b in enumerate (record .baseline )]
2038
+ record .file_name = record .n_sig * [record_name_out + '.wav' ]
2039
+ record .block_size = record .n_sig * [0 ]
2040
+ record .fmt = record .n_sig * ['16' ]
2041
+ record .samps_per_fram = record .n_sig * [1 ]
2042
+ record .init_value = sig_data [0 ][:record .n_sig ].tolist ()
2043
+ record .byte_offset = record .n_sig * [44 ]
2044
+ # Write the header file
2045
+ record .wrheader ()
2046
+
2047
+
1894
2048
def wav2mit (record_name , pn_dir = None , delete_file = True , record_only = False ):
1895
2049
"""
1896
2050
Convert .wav (format 16, multiplexed signals, with embedded header
0 commit comments