/* SignalProcessingChain.java created 2008-01-27 * */ package org.signalml.domain.signal; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.nio.channels.Pipe.SourceChannel; import java.util.Date; import org.apache.log4j.Logger; import org.signalml.app.SvarogApplication; import org.signalml.app.document.ManagedDocumentType; import org.signalml.app.document.mrud.MRUDEntry; import org.signalml.app.document.signal.RawSignalDocument; import org.signalml.app.document.signal.RawSignalMRUDEntry; import org.signalml.app.document.signal.SignalMLDocument; import org.signalml.app.document.signal.SignalMLMRUDEntry; import org.signalml.app.model.document.opensignal.SignalMLDescriptor; import org.signalml.app.model.document.opensignal.elements.SignalParameters; import org.signalml.codec.SignalMLCodec; import org.signalml.codec.SignalMLCodecReader; import org.signalml.domain.montage.Montage; import org.signalml.domain.montage.MontageChannel; import org.signalml.domain.montage.MontageMismatchException; import org.signalml.domain.signal.filter.MultichannelSampleFilter; import org.signalml.domain.signal.filter.export.MultichannelSampleFilterForExport; import org.signalml.domain.signal.raw.RawSignalDescriptor; import org.signalml.domain.signal.raw.RawSignalSampleSource; import org.signalml.domain.signal.samplesource.AbstractMultichannelSampleSource; import org.signalml.domain.signal.samplesource.MultichannelSampleSource; import org.signalml.domain.signal.samplesource.OriginalMultichannelSampleSource; import org.signalml.domain.signal.samplesource.SignalMLCodecSampleSource; import org.signalml.domain.signal.space.SignalSourceLevel; import org.signalml.exception.MissingCodecException; import org.signalml.exception.SanityCheckException; import org.signalml.math.iirdesigner.BadFilterParametersException; import org.signalml.plugin.export.SignalMLException; /** * This class represents the chain (series) of * {@link MultichannelSampleSource sample sources} from which the first * is the {@link OriginalMultichannelSampleSource original source of samples} * and the rest in the series is using previous as the source. * The types of sample sources in the series depend on the type of the chain. * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o. */ public class SignalProcessingChain extends AbstractMultichannelSampleSource implements MultichannelSampleSource, PropertyChangeListener { protected static final Logger logger = Logger.getLogger(SignalProcessingChain.class); private boolean createdSource; /** * the {@link OriginalMultichannelSampleSource original source} * of samples */ private OriginalMultichannelSampleSource source; /** * the {@link MultichannelSampleBuffer buffer} for the * {@link OriginalMultichannelSampleSource original source} of samples */ private MultichannelSampleBuffer sourceBuffer; /** * the {@link MultichannelSampleMontage source} of samples for * the montage */ private MultichannelSampleMontage montage; /** * the {@link MultichannelSampleBuffer buffer} for the * {@link MultichannelSampleMontage source} of samples for * the montage */ private MultichannelSampleBuffer montageBuffer; /** * the {@link MultichannelSampleFilter source} of samples * for the filter */ private MultichannelSampleFilter filter; /** * the last {@link MultichannelSampleSource sample source} in the * chain, used to return samples */ private MultichannelSampleSource output; /** * Constructor. Creates an empty processing chain based on a * given {@link OriginalMultichannelSampleSource original source} * and the {@link SignalType type} of the signal. * It doesn't provide the ability to return samples. * @param source the original source of the signal * @param signalType the type of the signal */ protected SignalProcessingChain(OriginalMultichannelSampleSource source) { super(); this.source = source; } /** * Constructor. Creates the processing chain using the given * {@link SignalProcessingChainDescriptor descriptor}. * @param descriptor the descriptor of the chain * @throws IOException if there is an error while reading samples from * file * @throws SignalMLException if codec doesn't exist or some other error * with the codec */ public SignalProcessingChain(SignalProcessingChainDescriptor descriptor) throws IOException, SignalMLException { super(); MRUDEntry mrud = descriptor.getDocument(); OriginalMultichannelSampleSource source = null; if (mrud instanceof SignalMLMRUDEntry) { SignalMLMRUDEntry smlEntry = (SignalMLMRUDEntry) mrud; String codecUID = smlEntry.getDescriptor().getCodecUID(); SignalMLCodec codec = SvarogApplication.getSharedInstance().getSignalMLCodecManager().getCodecByUID(codecUID); if (codec == null) { logger.warn("Mrud codec not found for uid [" + codecUID + "]"); throw new MissingCodecException("error.mrudMissingCodecException"); } SignalMLCodecReader reader = codec.createReader(); reader.open(smlEntry.getPath()); source = new SignalMLCodecSampleSource(reader); SignalParameters signalParameters = smlEntry.getDescriptor().getSignalParameters(); if (source.isCalibrationCapable()) { source.setCalibrationGain(signalParameters.getCalibrationGain()); } if (!source.isSamplingFrequencyCapable()) { source.setSamplingFrequency(signalParameters.getSamplingFrequency()); } if (!source.isChannelCountCapable()) { source.setChannelCount(signalParameters.getChannelCount()); } } else if (mrud instanceof RawSignalMRUDEntry) { RawSignalMRUDEntry rawEntry = (RawSignalMRUDEntry) mrud; RawSignalDescriptor rawDescriptor = rawEntry.getDescriptor(); source = new RawSignalSampleSource(rawEntry.getFile(), rawDescriptor.getChannelCount(), rawDescriptor.getSamplingFrequency(), rawDescriptor.getSampleType(), rawDescriptor.getByteOrder()); source.setCalibrationGain(rawDescriptor.getCalibrationGain()); source.setCalibrationOffset(rawDescriptor.getCalibrationOffset()); } else { throw new SanityCheckException("Don't know how to open this kind of mrud [" + mrud.getClass().getName() + "]"); } this.source = source; output = source; if (descriptor.isSourceBuffered()) { sourceBuffer = new MultichannelSampleBuffer(output, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); output = sourceBuffer; } if (descriptor.isAssembled()) { montage = new MultichannelSampleMontage(output); montage.setCurrentMontage(descriptor.getMontage()); output = montage; if (descriptor.isMontageBuffered()) { montageBuffer = new MultichannelSampleBuffer(output, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); output = montageBuffer; } } if (descriptor.isFiltered()) { filter = new MultichannelSampleFilter(output, source); filter.setCurrentMontage(descriptor.getMontage()); output = filter; } configureOutput(); } /** * Adds this chain as a listener for the output * {@link MultichannelSampleSource source}. */ protected void configureOutput() { output.addPropertyChangeListener(this); } @Override public void destroy() { output.removePropertyChangeListener(this); if (createdSource) { source.destroy(); } if (filter != null) { filter.destroy(); } if (montageBuffer != null) { montageBuffer.destroy(); } if (montage != null) { montage.destroy(); } if (sourceBuffer != null) { sourceBuffer.destroy(); } } /** * Creates the simplest possible chain where the * {@link OriginalMultichannelSampleSource original source} of samples * is also the output. * @param source the original source of samples * @param signalType the {@link SignalType type} of the signal * @return the created chain */ public static SignalProcessingChain createRawChain(OriginalMultichannelSampleSource source) { SignalProcessingChain chain = new SignalProcessingChain(source); chain.output = chain.source; chain.configureOutput(); return chain; } /** * Creates the chain of {@link MultichannelSampleSource sources} that * is buffered but doesn't contain any montage and is not filtered. * <code>original source = source -> buffer = output</code> * @param source the * {@link OriginalMultichannelSampleSource original source} of samples * @param signalType the {@link SignalType type} of the signal * @return the created chain */ public static SignalProcessingChain createBufferedRawChain(OriginalMultichannelSampleSource source) { SignalProcessingChain chain = new SignalProcessingChain(source); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.output = chain.sourceBuffer; chain.configureOutput(); return chain; } /** * Creates the chain: * <code>original source = source -> buffer -> montage = output</code> * @param source the * {@link OriginalMultichannelSampleSource original source} of samples * @param signalType the type of the signal * @return the created chain */ public static SignalProcessingChain createAssembledChain(OriginalMultichannelSampleSource source) { SignalProcessingChain chain = new SignalProcessingChain(source); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.montage = new MultichannelSampleMontage(chain.sourceBuffer); chain.output = chain.montage; chain.configureOutput(); return chain; } /** * Creates the chain: * <code>original source = source -> buffer -> montage * -> montage buffer = output</code> * @param source the * {@link OriginalMultichannelSampleSource original source} of samples * @param signalType the type of the signal * @return the created chain */ public static SignalProcessingChain createBufferedAssembledChain(OriginalMultichannelSampleSource source) { SignalProcessingChain chain = new SignalProcessingChain(source); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.montage = new MultichannelSampleMontage(chain.sourceBuffer); chain.montageBuffer = new MultichannelSampleBuffer(chain.montage, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.output = chain.montageBuffer; chain.configureOutput(); return chain; } /** * Creates the chain: * <code>original source = source -> montage * -> filter = output</code> * @param source the * {@link OriginalMultichannelSampleSource original source} of samples * @param signalType the type of the signal * @return the created chain */ public static SignalProcessingChain createNotBufferedFilteredChain(OriginalMultichannelSampleSource source) { SignalProcessingChain chain = new SignalProcessingChain(source); chain.montage = new MultichannelSampleMontage(chain.source); chain.filter = new MultichannelSampleFilter(chain.montage, source); chain.output = chain.filter; chain.configureOutput(); return chain; } public static SignalProcessingChain createFilteredChain(OriginalMultichannelSampleSource source) { SignalProcessingChain chain = new SignalProcessingChain(source); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.montage = new MultichannelSampleMontage(chain.sourceBuffer); chain.montageBuffer = new MultichannelSampleBuffer(chain.montage, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.filter = new MultichannelSampleFilter(chain.montageBuffer, source); chain.output = chain.filter; chain.configureOutput(); return chain; } // NOTE! buffering filtered chain is risky, so no "createBufferedFilterChain" - be sure to know what you're doing if you decide to implement one // (filtered fragments may not meet correctly at the edges?) /** * Creates the simplest possible chain where the * {@link OriginalMultichannelSampleSource original source} of samples * is also the output. * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * @param sampleSource the original source of samples * @return the created chain * @throws SignalMLException never */ protected SignalProcessingChain createRawLevelSharedChain(OriginalMultichannelSampleSource sampleSource) throws SignalMLException { SignalProcessingChain chain = new SignalProcessingChain(sampleSource); chain.output = chain.source; chain.configureOutput(); return chain; } /** * Creates the simplest possible chain where the * {@link OriginalMultichannelSampleSource original source} of samples * is also the output. * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same (shares) the original sample source with this chain. * @return the created chain * @throws SignalMLException never */ public SignalProcessingChain createRawLevelSharedChain() throws SignalMLException { return createRawLevelSharedChain(this.getSource()); } /** * Creates the simplest possible chain where the * {@link OriginalMultichannelSampleSource original source} of samples * is also the output. * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the copy of the original sample source from this chain. * @return the created chain * @throws SignalMLException if there is an error while duplicating * the original source */ public SignalProcessingChain createRawLevelCopyChain() throws SignalMLException { OriginalMultichannelSampleSource sampleSource = this.getSource().duplicate(); SignalProcessingChain chain = createRawLevelSharedChain(sampleSource); chain.createdSource = true; return chain; } /** * Creates the chain: * <code>original source = source -> buffer -> montage = output</code>. * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same {@link Montage montage} as it is used in this chain. * @param sampleSource the * {@link OriginalMultichannelSampleSource original source} of samples * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ protected SignalProcessingChain createAssembledLevelChain(OriginalMultichannelSampleSource sampleSource) throws SignalMLException { SignalProcessingChain chain = new SignalProcessingChain(sampleSource); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.montage = new MultichannelSampleMontage(chain.sourceBuffer); MultichannelSampleMontage baseMontage = this.getMontage(); if (baseMontage != null) { chain.montage.setCurrentMontage(baseMontage.getCurrentMontage()); } chain.output = chain.montage; chain.configureOutput(); return chain; } /** * Creates the chain: * <code>original source = source -> buffer -> montage = output</code>. * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same {@link Montage montage} as it is used in this chain. * Shares the {@link OriginalMultichannelSampleSource original source} * with this chain. * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ public SignalProcessingChain createAssembledLevelSharedChain() throws SignalMLException { return createAssembledLevelChain(this.getSource()); } /** * Creates the chain: * <code>original source = source -> buffer -> montage = output</code>. * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same {@link Montage montage} as it is used in this chain. * Uses the copy of the * {@link OriginalMultichannelSampleSource original source} from this * chain. * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ public SignalProcessingChain createAssembledLevelCopyChain() throws SignalMLException { OriginalMultichannelSampleSource sampleSource = this.getSource().duplicate(); SignalProcessingChain chain = createAssembledLevelChain(sampleSource); chain.createdSource = true; return chain; } /** * Creates the chain: * <code>original source = source -> buffer -> montage * -> montage buffer -> filter = output</code> * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same {@link Montage montage} as it is used in this chain. * @param sampleSource the * {@link OriginalMultichannelSampleSource original source} of samples * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ protected SignalProcessingChain createFilteredLevelChain(OriginalMultichannelSampleSource sampleSource) throws SignalMLException { SignalProcessingChain chain = new SignalProcessingChain(sampleSource); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.montage = new MultichannelSampleMontage(chain.sourceBuffer); // no montage buffer is used chain.filter = new MultichannelSampleFilter(chain.montage, sampleSource); MultichannelSampleMontage baseMontage = this.getMontage(); if (baseMontage != null) { Montage currentBaseMontage = baseMontage.getCurrentMontage(); chain.montage.setCurrentMontage(currentBaseMontage); chain.filter.setCurrentMontage(currentBaseMontage); } chain.output = chain.filter; chain.configureOutput(); return chain; } protected SignalProcessingChain createFilteredForExportLevelChain(OriginalMultichannelSampleSource sampleSource) throws SignalMLException { SignalProcessingChain chain = new SignalProcessingChain(sampleSource); chain.sourceBuffer = new MultichannelSampleBuffer(chain.source, MultichannelSampleBuffer.INITIAL_BUFFER_SIZE); chain.montage = new MultichannelSampleMontage(chain.sourceBuffer); // no montage buffer is used MultichannelSampleMontage baseMontage = this.getMontage(); if (baseMontage != null) { Montage currentBaseMontage = baseMontage.getCurrentMontage(); chain.montage.setCurrentMontage(currentBaseMontage); try { chain.filter = new MultichannelSampleFilterForExport(chain.montage, currentBaseMontage); } catch (BadFilterParametersException e) { // TODO Auto-generated catch block logger.error("", e); } catch (IOException e) { // TODO Auto-generated catch block logger.error("", e); } //chain.filter.setCurrentMontage(currentBaseMontage); } chain.output = chain.filter; chain.configureOutput(); return chain; } /** * Creates the chain: * <code>original source = source -> buffer -> montage * -> montage buffer -> filter = output</code> * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same {@link Montage montage} as it is used in this chain. * Shares the {@link OriginalMultichannelSampleSource original source} * with this chain. * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ public SignalProcessingChain createFilteredLevelSharedChain() throws SignalMLException { return createFilteredLevelChain(this.getSource()); } /** * Creates the chain: * <code>original source = source -> buffer -> montage * -> montage buffer -> filter = output</code> * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same {@link Montage montage} as it is used in this chain. * Uses the copy of the * {@link OriginalMultichannelSampleSource original source} from this * chain. * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ public SignalProcessingChain createFilteredLevelCopyChain() throws SignalMLException { OriginalMultichannelSampleSource sampleSource = this.getSource().duplicate(); SignalProcessingChain chain = createFilteredLevelChain(sampleSource); chain.createdSource = true; return chain; } public SignalProcessingChain createFilteredForExportLevelCopyChain() throws SignalMLException { OriginalMultichannelSampleSource sampleSource = this.getSource().duplicate(); SignalProcessingChain chain = createFilteredForExportLevelChain(sampleSource); chain.createdSource = true; return chain; } /** * Creates the chain of the given {@link SignalSourceLevel level}. * FILTERED: * <code>original source = source -> buffer -> montage * -> montage buffer -> filter = output</code> * ASSEMBLED: * <code>original source = source -> buffer -> montage * -> montage buffer = output</code> * RAW: * <code>original source = source = output</code> * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the same (shares) * {@link OriginalMultichannelSampleSource original source} as in this * chain. * If necessary uses the same {@link Montage montage} as it is used * in this chain. * @param level the desired level of the chain * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ public SignalProcessingChain createLevelSharedChain(SignalSourceLevel level) throws SignalMLException { switch (level) { case FILTERED : return createFilteredLevelSharedChain(); case ASSEMBLED : return createAssembledLevelSharedChain(); case RAW : default : return createRawLevelSharedChain(); } } /** * Creates the chain of the given {@link SignalSourceLevel level}. * FILTERED: * <code>original source = source -> buffer -> montage * -> montage buffer -> filter = output</code> * ASSEMBLED: * <code>original source = source -> buffer -> montage * -> montage buffer = output</code> * RAW: * <code>original source = source = output</code> * Uses the same the {@link SignalType type} of the signal as it is used * in this chain. * Uses the copy of the * {@link OriginalMultichannelSampleSource original source} from this * chain. * If necessary uses the same {@link Montage montage} as it is used * in this chain. * @param level the desired level of the chain * @return the created chain * @throws SignalMLException if the number of channels in * the original source is different then the number of source * channels in the montage. */ public SignalProcessingChain createLevelCopyChain(SignalSourceLevel level) throws SignalMLException { switch (level) { case FILTERED_FOR_EXPORT: return createFilteredForExportLevelCopyChain(); case FILTERED : return createFilteredLevelCopyChain(); case ASSEMBLED : return createAssembledLevelCopyChain(); case RAW : default : return createRawLevelCopyChain(); } } /** * Creates the {@link SignalProcessingChainDescriptor descriptor} * describing this chain and stores in it all possible information. * @return the created descriptor */ public SignalProcessingChainDescriptor createDescriptor() { SignalProcessingChainDescriptor descriptor = new SignalProcessingChainDescriptor(); descriptor.setFiltered(filter != null); descriptor.setMontageBuffered(montageBuffer != null); if (montage != null) { descriptor.setAssembled(true); descriptor.setMontage(new Montage(montage.getCurrentMontage())); } else { descriptor.setAssembled(false); descriptor.setMontage(null); } descriptor.setSourceBuffered(sourceBuffer != null); SignalParameters signalParameters = new SignalParameters(); signalParameters.setPageSize(-1F); signalParameters.setBlocksPerPage(-1); signalParameters.setSamplingFrequency(source.getSamplingFrequency()); signalParameters.setChannelCount(source.getChannelCount()); signalParameters.setChannelCount(source.getChannelCount()); if (source instanceof SignalMLCodecSampleSource) { SignalMLCodecSampleSource codecSource = (SignalMLCodecSampleSource) source; SignalMLCodecReader reader = codecSource.getReader(); SignalMLDescriptor signalMLDescriptor = new SignalMLDescriptor(); signalMLDescriptor.setSignalParameters(signalParameters); SignalMLMRUDEntry mrud = new SignalMLMRUDEntry(ManagedDocumentType.SIGNAL, SignalMLDocument.class, reader.getCurrentFilename(), signalMLDescriptor); mrud.setLastTimeOpened(new Date()); descriptor.setDocument(mrud); } else if (source instanceof RawSignalSampleSource) { RawSignalSampleSource rawSource = (RawSignalSampleSource) source; RawSignalDescriptor rawDescriptor = new RawSignalDescriptor(); signalParameters.setCalibrationGain(source.getCalibrationGain()); signalParameters.setCalibrationOffset(source.getCalibrationOffset()); rawDescriptor.setSignalParameters(signalParameters); rawDescriptor.setSampleCount(rawSource.getSampleCount()); rawDescriptor.setSampleType(rawSource.getSampleType()); rawDescriptor.setByteOrder(rawSource.getByteOrder()); RawSignalMRUDEntry mrud = new RawSignalMRUDEntry(ManagedDocumentType.SIGNAL, RawSignalDocument.class, rawSource.getFile().getAbsolutePath(), rawDescriptor); mrud.setLastTimeOpened(new Date()); descriptor.setDocument(mrud); } else { throw new SanityCheckException("Unsupported sample source type: " + source.getClass().getName()); } return descriptor; } @Override public int getChannelCount() { return output.getChannelCount(); } @Override public int getDocumentChannelIndex(int channel) { return output.getDocumentChannelIndex(channel); } @Override public String getLabel(int channel) { return output.getLabel(channel); } @Override public int getSampleCount(int channel) { return output.getSampleCount(channel); } @Override public void getSamples(int channel, double[] target, int signalOffset, int count, int arrayOffset) { output.getSamples(channel, target, signalOffset, count, arrayOffset); } @Override public float getSamplingFrequency() { return output.getSamplingFrequency(); } /** * Returns if the last source in the chain (<code>output</code> * is capable of returning a channel count * @return true if the last source in the chain (<code>output</code> * is capable of returning a channel count, false otherwise */ @Override public boolean isChannelCountCapable() { return output.isChannelCountCapable(); } /** * Returns if the last source in the chain (<code>output</code> * is capable of returning a sampling frequency * @return true if the last source in the chain (<code>output</code> * is capable of returning a sampling frequency, false otherwise */ @Override public boolean isSamplingFrequencyCapable() { return output.isSamplingFrequencyCapable(); } /** * Fires all listeners that this chain has changed * @param evt an event describing the change */ @Override public void propertyChange(PropertyChangeEvent evt) { pcSupport.firePropertyChange(evt); } /** * Returns the {@link OriginalMultichannelSampleSource original source} * of samples. * @return the original source of samples */ public OriginalMultichannelSampleSource getSource() { return source; } /** * Returns the {@link MultichannelSampleBuffer buffer} for the * {@link OriginalMultichannelSampleSource original source} of samples. * @return the buffer for the original source of samples. */ public MultichannelSampleBuffer getSourceBuffer() { return sourceBuffer; } /** * Returns the {@link MultichannelSampleMontage source} of samples for * the montage. * @return the source of samples for the montage */ public MultichannelSampleMontage getMontage() { return montage; } /** * Returns the {@link MultichannelSampleBuffer buffer} for the * {@link MultichannelSampleMontage source} of samples for * the montage. * @return the buffer for the source of samples for the montage */ public MultichannelSampleBuffer getMontageBuffer() { return montageBuffer; } /** * Returns the {@link MultichannelSampleFilter source} of samples * for the filter. * @return the source of samples for the filter. */ public MultichannelSampleFilter getFilter() { return filter; } /** * Returns the last {@link MultichannelSampleSource source} * in the chain. * @return the last source in the chain */ public MultichannelSampleSource getOutput() { return output; } /** * Changes the actual {@link Montage montage} in the * {@link MultichannelSampleMontage source} of samples for the montage * and in the {@link MultichannelSampleFilter source} of samples for the * filter * @param montageDef the new montage to be set * @throws MontageMismatchException if the number of source channels in * the montage is different then the number of channels in the source */ public void applyMontageDefinition(Montage montageDef) throws MontageMismatchException { if (montage != null) { montage.setCurrentMontage(montageDef); } if (filter != null) { filter.setCurrentMontage(montageDef); } } /** * Changes the actual {@link Montage montage} in the * {@link MultichannelSampleMontage source} of samples for the montage * but doesn't change it in the {@link MultichannelSampleFilter source} * of samples for the filter. * * Therefore, it should only be used when filters did not change. * * @param montageDef the new montage to be set * @throws MontageMismatchException if the number of source channels in * the montage is different then the number of channels in the source */ public void applyMontageDefinitionWithoutfilters(Montage montageDef) throws MontageMismatchException { if (montage != null) { montage.setCurrentMontage(montageDef); } } /** * Returns indexes of {@link MontageChannel montage channels} in the * {@link Montage montage} in which the given * {@link SourceChannel source channel} is the primary channel. * If there is no montage only index of provided channel is returned. * @param channel the index of the source channel * @return an array of indexes of montage channels in which * the given source channel is the primary channel. */ public int[] getDependantChannelIndices(int channel) { if (montage == null) { return new int[] { channel }; } else { return montage.getMontageChannelIndices(channel); } } /** * Returns an array of labels of channels in the <code>output</code> * {@link MultichannelSampleSource source} of samples. * @return an array of labels of channels in the <code>output</code> * source of samples */ public String[] getLabels() { if (montage == null) { int channelCount = getChannelCount(); String[] labels = new String[channelCount]; for (int i=0; i<channelCount; i++) { labels[i] = getLabel(i); } return labels; } else { return montage.getLabels(); } } /** * Returns the label of the {@link SourceChannel source channel} of a * given index * @param channel the index of a channel * @return string with a label of the channel */ public String getPrimaryLabel(int channel) { if (montage == null) { return output.getLabel(channel); } else { return montage.getPrimaryLabel(channel); } } }