Write a dat file. All bytes are written one at a time to avoid
    endianness issues.

def wr_dat_file(file_name, fmt, d_signal, byte_offset, expanded=False,
                e_d_signal=None, samps_per_frame=None, write_dir=''):
    """
    Write a dat file. All bytes are written one at a time to avoid
    endianness issues.

    """
    # Combine list of arrays into single array
    if expanded:
        n_sig = len(e_d_signal)
        sig_len = int(len(e_d_signal[0])/samps_per_frame[0])
        # Effectively create MxN signal, with extra frame samples acting
        # like extra channels
        d_signal = np.zeros((sig_len, sum(samps_per_frame)), dtype = 'int64')
        # Counter for channel number
        expand_ch = 0
        for ch in range(n_sig):
            spf = samps_per_frame[ch]
            for framenum in range(spf):
                d_signal[:, expand_ch] = e_d_signal[ch][framenum::spf]
                expand_ch = expand_ch + 1

    # This n_sig is used for making list items.
    # Does not necessarily represent number of signals (ie. for expanded=True)
    n_sig = d_signal.shape[1]

    if fmt == '80':
        # convert to 8 bit offset binary form
        d_signal = d_signal + 128
        # Concatenate into 1D
        d_signal = d_signal.reshape(-1)
        # Convert to un_signed 8 bit dtype to write
        b_write = d_signal.astype('uint8')

    elif fmt == '212':
        # Each sample is represented by a 12 bit two's complement
        # amplitude. The first sample is obtained from the 12 least
        # significant bits of the first byte pair (stored least
        # significant byte first). The second sample is formed from the
        # 4 remaining bits of the first byte pair (which are the 4 high
        # bits of the 12-bit sample) and the next byte (which contains
        # the remaining 8 bits of the second sample). The process is
        # repeated for each successive pair of samples.

        # convert to 12 bit two's complement
        d_signal[d_signal<0] = d_signal[d_signal<0] + 4096

        # Concatenate into 1D
        d_signal = d_signal.reshape(-1)

        n_samp = len(d_signal)
        # use this for byte processing
        processn_samp = n_samp

        # Odd numbered number of samples. Fill in extra blank for
        # following byte calculation.
        if processn_samp % 2:
            d_signal = np.concatenate([d_signal, np.array([0])])
            processn_samp +=1

        # The individual bytes to write
        b_write = np.zeros([int(1.5*processn_samp)], dtype = 'uint8')

        # Fill in the byte triplets

        # Triplet 1 from lowest 8 bits of sample 1
        b_write[0::3] = d_signal[0::2] & 255
        # Triplet 2 from highest 4 bits of samples 1 (lower) and 2 (upper)
        b_write[1::3] = ((d_signal[0::2] & 3840) >> 8) + ((d_signal[1::2] & 3840) >> 4)
        # Triplet 3 from lowest 8 bits of sample 2
        b_write[2::3] = d_signal[1::2] & 255

        # If we added an extra sample for byte calculation, remove the last byte (don't write)
        if n_samp % 2:
            b_write = b_write[:-1]

    elif fmt == '16':
        # convert to 16 bit two's complement
        d_signal[d_signal<0] = d_signal[d_signal<0] + 65536
        # Split samples into separate bytes using binary masks
        b1 = d_signal & [255]*n_sig
        b2 = ( d_signal & [65280]*n_sig ) >> 8
        # Interweave the bytes so that the same samples' bytes are consecutive
        b1 = b1.reshape((-1, 1))
        b2 = b2.reshape((-1, 1))
        b_write = np.concatenate((b1, b2), axis=1)
        b_write = b_write.reshape((1,-1))[0]
        # Convert to un_signed 8 bit dtype to write
        b_write = b_write.astype('uint8')
    elif fmt == '24':
        # convert to 24 bit two's complement
        d_signal[d_signal<0] = d_signal[d_signal<0] + 16777216
        # Split samples into separate bytes using binary masks
        b1 = d_signal & [255]*n_sig
        b2 = ( d_signal & [65280]*n_sig ) >> 8
        b3 = ( d_signal & [16711680]*n_sig ) >> 16
        # Interweave the bytes so that the same samples' bytes are consecutive
        b1 = b1.reshape((-1, 1))
        b2 = b2.reshape((-1, 1))
        b3 = b3.reshape((-1, 1))
        b_write = np.concatenate((b1, b2, b3), axis=1)
        b_write = b_write.reshape((1,-1))[0]
        # Convert to un_signed 8 bit dtype to write
        b_write = b_write.astype('uint8')

    elif fmt == '32':
        # convert to 32 bit two's complement
        d_signal[d_signal<0] = d_signal[d_signal<0] + 4294967296
        # Split samples into separate bytes using binary masks
        b1 = d_signal & [255]*n_sig
        b2 = ( d_signal & [65280]*n_sig ) >> 8
        b3 = ( d_signal & [16711680]*n_sig ) >> 16
        b4 = ( d_signal & [4278190080]*n_sig ) >> 24
        # Interweave the bytes so that the same samples' bytes are consecutive
        b1 = b1.reshape((-1, 1))
        b2 = b2.reshape((-1, 1))
        b3 = b3.reshape((-1, 1))
        b4 = b4.reshape((-1, 1))
        b_write = np.concatenate((b1, b2, b3, b4), axis=1)
        b_write = b_write.reshape((1,-1))[0]
        # Convert to un_signed 8 bit dtype to write
        b_write = b_write.astype('uint8')
    else:
        raise ValueError('This library currently only supports writing the following formats: 80, 16, 24, 32')

    # Byte offset in the file
    if byte_offset is not None and byte_offset>0:
        print('Writing file '+file_name+' with '+str(byte_offset)+' empty leading bytes')
        b_write = np.append(np.zeros(byte_offset, dtype = 'uint8'), b_write)

    # Write the bytes to the file
    with open(os.path.join(write_dir, file_name),'wb') as f:
        b_write.tofile(f)