/* RawSignalWriter.java created 2008-01-28 * */ package org.signalml.domain.signal.raw; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.DoubleBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import org.signalml.app.model.signal.SignalExportDescriptor; import org.signalml.app.view.signal.SampleSourceUtils; import org.signalml.domain.signal.SignalWriterMonitor; import org.signalml.domain.signal.export.ISignalWriter; import org.signalml.domain.signal.samplesource.MultichannelSampleSource; import org.signalml.domain.signal.samplesource.MultichannelSegmentedSampleSource; import org.signalml.exception.SanityCheckException; /** * This class is responsible for writing the raw signal (or its part) * to the file or to the stream. * To determine the format uses provided {@link SignalExportDescriptor descriptor}. * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o. */ public class RawSignalWriter implements ISignalWriter { /** * the size of the buffer (number of samples) */ private int maximumBufferSize = 8192; public void setMaximumBufferSize(int maximumBufferSize) { this.maximumBufferSize = maximumBufferSize; } /** * Writes the fragment of the signal from the specified * {@link MultichannelSampleSource source} to the specified file * based on the given {@link SignalExportDescriptor description}. * @param signalFile the file to which the signal will written * @param sampleSource the {@link MultichannelSampleSource source} of * signal samples * @param descriptor the {@link SignalExportDescriptor description} * of the signal * @param firstSample the index of the first sample that will be * written to file * @param sampleCount the number of samples that are to be written to * file * @param monitor the {@link SignalWriterMonitor monitor} which monitors * the process of writing signal to file and can request its abortion * @throws IOException if there is an error while writing bytes * to file */ public void writeSignal(File signalFile, MultichannelSampleSource sampleSource, SignalExportDescriptor descriptor, int firstSample, int sampleCount, SignalWriterMonitor monitor) throws IOException { OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(signalFile)); writeSignal(os, sampleSource, descriptor, firstSample, sampleCount, monitor); } finally { if (os != null) { try { os.close(); } catch (IOException ex) { // ignore } } } } /** * Writes the fragment of the signal from the specified * {@link MultichannelSampleSource source} to the specified stream * based on the given {@link SignalExportDescriptor description}. * @param os the stream to which the signal will written * @param sampleSource the {@link MultichannelSampleSource source} of * signal samples * @param descriptor the {@link SignalExportDescriptor description} * of the signal * @param firstSample the index of the first sample that will be * written to the stream * @param sampleCount the number of samples that are to be written to * the stream * @param monitor the {@link SignalWriterMonitor monitor} which monitors * the process of writing signal to the stream and can request its * abortion * @throws IOException if there is an error while writing bytes * to the stream */ public void writeSignal(OutputStream os, MultichannelSampleSource sampleSource, SignalExportDescriptor descriptor, int firstSample, int sampleCount, SignalWriterMonitor monitor) throws IOException { int bufferSize = Math.min(maximumBufferSize, sampleCount); RawSignalSampleType sampleType = descriptor.getSampleType(); int sampleByteSize = sampleType.getByteWidth(); int channelCount = sampleSource.getChannelCount(); double[][] data = new double[channelCount][bufferSize]; double[] dMultiBuffer = null; float[] fMultiBuffer = null; int[] iMultiBuffer = null; short[] sMultiBuffer = null; DoubleBuffer dBuffer = null; FloatBuffer fBuffer = null; IntBuffer iBuffer = null; ShortBuffer sBuffer = null; int multiSampleCount = channelCount*bufferSize; int cnt = 0; int length = channelCount * sampleCount; byte[] byteBuffer = new byte[multiSampleCount*sampleByteSize]; ByteBuffer bBuffer = ByteBuffer.wrap(byteBuffer).order(descriptor.getByteOrder().getByteOrder()); switch (sampleType) { case DOUBLE : dMultiBuffer = new double[multiSampleCount]; dBuffer = bBuffer.asDoubleBuffer(); break; case FLOAT : fMultiBuffer = new float[multiSampleCount]; fBuffer = bBuffer.asFloatBuffer(); break; case INT : iMultiBuffer = new int[multiSampleCount]; iBuffer = bBuffer.asIntBuffer(); break; case SHORT : sMultiBuffer = new short[multiSampleCount]; sBuffer = bBuffer.asShortBuffer(); break; default : throw new SanityCheckException("Unsupported type [" + sampleType + "]"); } int bOffset; int channel = 0; int sample = 0; int currentSample = firstSample; int toGetCnt = 0; int samplesRemaining = sampleCount; int i; boolean normalize = descriptor.isNormalize(); double normalizationFactor; if (normalize) { normalizationFactor = descriptor.getNormalizationFactor(); } else { normalizationFactor = 1.0; } do { if (monitor != null && monitor.isRequestingAbort()) { return; } toGetCnt = Math.min(bufferSize, samplesRemaining); // get samples for all channels for (i=0; i<channelCount; i++) { sampleSource.getSamples(i, data[i], currentSample, toGetCnt, 0); } samplesRemaining -= toGetCnt; currentSample += toGetCnt; sample = 0; bOffset = 0; switch (sampleType) { case DOUBLE: // multiplex samples for (; cnt<length && bOffset<multiSampleCount; cnt++) { dMultiBuffer[bOffset] = (data[channel][sample] * normalizationFactor); bOffset++; channel = (channel+1) % channelCount; if (channel == 0) { sample++; } } // enforce byte order dBuffer.clear(); dBuffer.put(dMultiBuffer, 0, bOffset); break; case FLOAT: // multiplex samples for (; cnt<length && bOffset<multiSampleCount; cnt++) { fMultiBuffer[bOffset] = (float)(data[channel][sample] * normalizationFactor); bOffset++; channel = (channel+1) % channelCount; if (channel == 0) { sample++; } } // enforce byte order fBuffer.clear(); fBuffer.put(fMultiBuffer, 0, bOffset); break; case INT: // multiplex samples for (; cnt<length && bOffset<multiSampleCount; cnt++) { iMultiBuffer[bOffset] = (int) Math.round((data[channel][sample] * normalizationFactor)); bOffset++; channel = (channel+1) % channelCount; if (channel == 0) { sample++; } } // enforce byte order iBuffer.clear(); iBuffer.put(iMultiBuffer, 0, bOffset); break; case SHORT: // multiplex samples for (; cnt<length && bOffset<multiSampleCount; cnt++) { sMultiBuffer[bOffset] = (short) Math.round((data[channel][sample] * normalizationFactor)); bOffset++; channel = (channel+1) % channelCount; if (channel == 0) { sample++; } } // enforce byte order sBuffer.clear(); sBuffer.put(sMultiBuffer, 0, bOffset); break; default: break; } // write samples os.write(byteBuffer, 0, bOffset*sampleByteSize); if (monitor != null) { monitor.setProcessedSampleCount(currentSample - firstSample); } } while (cnt < length); } /** * Writes the whole signal from the specified * {@link MultichannelSampleSource source} to the specified file * based on the given {@link SignalExportDescriptor description}. * @param signalFile the file to which the signal will written * @param sampleSource the {@link MultichannelSampleSource source} of * signal samples * @param descriptor the {@link SignalExportDescriptor description} * of the signal * @param monitor the {@link SignalWriterMonitor monitor} which monitors * the process of writing signal to file and can request its abortion * @throws IOException if there is an error while writing bytes * to file */ @Override public void writeSignal(File signalFile, MultichannelSampleSource sampleSource, SignalExportDescriptor descriptor, SignalWriterMonitor monitor) throws IOException { int sampleCount = SampleSourceUtils.getMinSampleCount(sampleSource); writeSignal(signalFile, sampleSource, descriptor, 0, sampleCount, monitor); } /** * Writes the whole signal from the specified * {@link MultichannelSampleSource source} to the specified stream * based on the given {@link SignalExportDescriptor description}. * @param os the stream to which the signal will written * @param sampleSource the {@link MultichannelSampleSource source} of * signal samples * @param descriptor the {@link SignalExportDescriptor description} * of the signal * @param monitor the {@link SignalWriterMonitor monitor} which monitors * the process of writing signal to the stream and can request its abortion * @throws IOException if there is an error while writing bytes * to the stream */ public void writeSignal(OutputStream os, MultichannelSampleSource sampleSource, SignalExportDescriptor descriptor, SignalWriterMonitor monitor) throws IOException { int sampleCount = SampleSourceUtils.getMinSampleCount(sampleSource); writeSignal(os, sampleSource, descriptor, 0, sampleCount, monitor); } /** * Writes the specified segment of the signal from the specified * {@link MultichannelSampleSource source} to the specified file * based on the given {@link SignalExportDescriptor description}. * @param signalFile the file to which the signal will written * @param sampleSource the * {@link MultichannelSegmentedSampleSource source} of signal samples * @param descriptor the {@link SignalExportDescriptor description} * of the signal * @param segment the index of the segment in the source * @param monitor the {@link SignalWriterMonitor monitor} which monitors * the process of writing signal to file and can request its abortion * @throws IOException if there is an error while writing bytes * to file */ public void writeSignal(File signalFile, MultichannelSegmentedSampleSource sampleSource, SignalExportDescriptor descriptor, int segment, SignalWriterMonitor monitor) throws IOException { int sampleCount = sampleSource.getSegmentLengthInSamples(); writeSignal(signalFile, sampleSource, descriptor, segment * sampleSource.getSegmentLengthInSamples(), sampleCount, monitor); } /** * Writes the specified segment of the signal from the specified * {@link MultichannelSampleSource source} to the specified stream * based on the given {@link SignalExportDescriptor description}. * @param os the stream to which the signal will written * @param sampleSource the * {@link MultichannelSegmentedSampleSource source} of signal samples * @param descriptor the {@link SignalExportDescriptor description} * of the signal * @param segment the index of the segment in the source * @param monitor the {@link SignalWriterMonitor monitor} which monitors * the process of writing signal to the stream and can request its * abortion * @throws IOException if there is an error while writing bytes * to the stream */ public void writeSignal(OutputStream os, MultichannelSegmentedSampleSource sampleSource, SignalExportDescriptor descriptor, int segment, SignalWriterMonitor monitor) throws IOException { int sampleCount = sampleSource.getSegmentLengthInSamples(); writeSignal(os, sampleSource, descriptor, segment * sampleSource.getSegmentLengthInSamples(), sampleCount, monitor); } }