Beispiel #1
0
// Base code for adding, removing, moving and duplicating instruments. Returns new number of instruments on success, INSTRUMENTINDEX_INVALID otherwise.
// The new instrument vector can contain INSTRUMENTINDEX_INVALID for adding new (empty) instruments.
// newOrder indices are zero-based, i.e. newOrder[0] will define the contents of the first instrument slot.
INSTRUMENTINDEX CModDoc::ReArrangeInstruments(const std::vector<INSTRUMENTINDEX> &newOrder, deleteInstrumentSamples removeSamples)
//--------------------------------------------------------------------------------------------------------------------------------
{
	if(newOrder.size() > m_SndFile.GetModSpecifications().instrumentsMax || GetNumInstruments() == 0)
	{
		return INSTRUMENTINDEX_INVALID;
	}

	CriticalSection cs;

	const INSTRUMENTINDEX oldNumInstruments = m_SndFile.GetNumInstruments(), newNumInstruments = static_cast<INSTRUMENTINDEX>(newOrder.size());

	std::vector<ModInstrument> instrumentHeaders(oldNumInstruments + 1);
	std::vector<INSTRUMENTINDEX> newIndex(oldNumInstruments + 1, 0);	// One of the new indexes for the old instrument
	for(INSTRUMENTINDEX i = 0; i < newNumInstruments; i++)
	{
		const INSTRUMENTINDEX origSlot = newOrder[i];
		if(origSlot > 0 && origSlot <= oldNumInstruments)
		{
			if(m_SndFile.Instruments[origSlot] != nullptr)
				instrumentHeaders[origSlot] = *m_SndFile.Instruments[origSlot];
			newIndex[origSlot] = i + 1;
		}
	}

	// Delete unused instruments first.
	for(INSTRUMENTINDEX i = 1; i <= oldNumInstruments; i++)
	{
		if(newIndex[i] == 0)
		{
			m_SndFile.DestroyInstrument(i, removeSamples);
		}
	}

	m_SndFile.m_nInstruments = newNumInstruments;

	// Now, create new instrument list.
	for(INSTRUMENTINDEX i = 0; i < newNumInstruments; i++)
	{
		ModInstrument *ins = m_SndFile.AllocateInstrument(i + 1);
		if(ins == nullptr)
		{
			continue;
		}

		const INSTRUMENTINDEX origSlot = newOrder[i];
		if(origSlot > 0 && origSlot <= oldNumInstruments)
		{
			// Copy an original instrument.
			*ins = instrumentHeaders[origSlot];
		}
	}

	// Free unused instruments
	for(INSTRUMENTINDEX i = newNumInstruments + 1; i <= oldNumInstruments; i++)
	{
		m_SndFile.DestroyInstrument(i, doNoDeleteAssociatedSamples);
	}

	PrepareUndoForAllPatterns(false, "Rearrange Instrumens");
	GetInstrumentUndo().RearrangeInstruments(newIndex);

	std::vector<ModCommand::INSTR> indices(newIndex.size(), 0);
	for(size_t i = 0; i < newIndex.size(); i++)
	{
		indices[i] = newIndex[i];
	}
	m_SndFile.Patterns.ForEachModCommand(RewriteInstrumentReferencesInPatterns(indices));

	return GetNumInstruments();
}
 /**
  * Read the file designated by @a filename and fill @a output.
  */
 void BSFFileIO::Read(const std::string& filename, Acquisition::Pointer output)
 {
   output->Reset();
   IEEELittleEndianBinaryFileStream bifs;
   bifs.SetExceptions(BinaryFileStream::EndFileBit | BinaryFileStream::FailBit | BinaryFileStream::BadBit);
   try
   {
     bifs.Open(filename, BinaryFileStream::In);
     // Main header (SMnHeaderTag)
     if (bifs.ReadI32() != 100)
       throw BSFFileIOException("Invalid BSF file.");
     int32_t headerSize = bifs.ReadI32();
     int32_t numberOfActivePlatforms = bifs.ReadI32();
     int32_t numberOfActiveInstruments = bifs.ReadI32();
     std::string subjectName = btkTrimString(bifs.ReadString(100));
     std::string testDate = btkTrimString(bifs.ReadString(12));
     std::string subjectDateOfBirth = btkTrimString(bifs.ReadString(12));
     double weight = bifs.ReadDouble();
     double height = bifs.ReadDouble();
     std::string sex = btkTrimString(bifs.ReadString(1));
     bifs.SeekRead(3, BinaryFileStream::Current); // Because of "pragma pack(4)": minimum of 4 bytes in the alignment of a member.
     int32_t numberOfTrials = bifs.ReadI32();
     double totaleTimeTrial = bifs.ReadDouble(); // seconds
     int32_t zeroMethod = bifs.ReadI32();
     int32_t weightMethod = bifs.ReadI32();
     int32_t delayAfterKeystroke = bifs.ReadI32();
     int32_t triggerMethod = bifs.ReadI32();
     int32_t triggerPlatform = bifs.ReadI32();
     int32_t preTriggerValue = bifs.ReadI32();
     int32_t postTriggerValue = bifs.ReadI32();
     double triggerValue = bifs.ReadDouble();
     bifs.SeekRead(4, BinaryFileStream::Current); // FIXME: There is 4 extra bytes in the file used to test this reader! What are they?
     int32_t rate = bifs.ReadI32();
     std::string protocol = btkTrimString(bifs.ReadString(150));
     std::string testType = btkTrimString(bifs.ReadString(200));
     std::string commentFile = btkTrimString(bifs.ReadString(150));
     std::string trialDescriptionFile = btkTrimString(bifs.ReadString(150));
     std::string examinerName = btkTrimString(bifs.ReadString(100));
     bifs.SeekRead(2, BinaryFileStream::Current); // WARNING: Two (2) extra bytes in the file tested. Could be for alignment?
     int32_t units = bifs.ReadI32(); // 0: english, 1: metric
     
     if (rate == 0)
       throw BSFFileIOException("Invalid frame rate.");
     
     // Instrument headers (SInstrHeaderTag)
     std::vector<InstrumentHeader> instrumentHeaders(numberOfActivePlatforms + numberOfActiveInstruments);
     for (int i = 0 ; i < numberOfActivePlatforms ; ++i)
       this->extractInstrumentHeader(&bifs, &(instrumentHeaders[i]));
     for (int i = 0 ; i < numberOfActiveInstruments ; ++i)
       this->extractInstrumentHeader(&bifs, &(instrumentHeaders[i+numberOfActivePlatforms]));
     
     // Internal check to verify the compatibility between BTK acquisition's format and data
     for (size_t i = 0 ; i < instrumentHeaders.size() ; ++i)
     {
       if ((instrumentHeaders[i].rate != 0) && (instrumentHeaders[i].rate != rate))
         throw BSFFileIOException("Unsupported file: An instrument has a different rate. Contact the developers to improve this reader.");
     }
     for (int i = 0 ; i < numberOfActivePlatforms ; ++i)
     {
       if (instrumentHeaders[i].numberOfChannels != 6)
         throw BSFFileIOException("Unsupported file: A force platform has more than 6 channels. Contact the developers to improve this reader.");
     }
     
     // Init
     int totalNumberOfChannels = 0;
     for (size_t i = 0 ; i < instrumentHeaders.size() ; ++i)
       totalNumberOfChannels += instrumentHeaders[i].numberOfChannels;
     double* scale = new double[totalNumberOfChannels]; // array to transform ADC values to real values
     size_t inc = 0;
     for (size_t i = 0 ; i < instrumentHeaders.size() ; ++i)
     {
       for (int j = 0 ; j < instrumentHeaders[i].numberOfChannels ; ++j)
         scale[j+inc] = 1000000.0 / (instrumentHeaders[i].sensitivity[j] * instrumentHeaders[i].amplifierGain[j] * instrumentHeaders[i].excitationVoltage[j] * instrumentHeaders[i].acquisitionCardRange[j]);
       inc += instrumentHeaders[i].numberOfChannels;
     }
     output->Init(0, static_cast<int>(totaleTimeTrial * static_cast<double>(rate)), totalNumberOfChannels);
     output->SetPointFrequency(static_cast<double>(rate));
     if (units == 0) // english
     {
       output->SetPointUnit(Point::Marker, "in");
       output->SetPointUnit(Point::Force, "lb");
       output->SetPointUnit(Point::Moment, "in-lb");
     }
     else
     {
       // The FP length/width seems to be set everytime in inch even if the header is set 
       // to metric units (so only used for measured value?).
       for (size_t i = 0 ; i < instrumentHeaders.size() ; ++i)
       {
          // Convert from inch to meter
         instrumentHeaders[i].length *= 0.0254f;
         instrumentHeaders[i].width *= 0.0254f;
         instrumentHeaders[i].offset[0] *= 0.0254f;
         instrumentHeaders[i].offset[1] *= 0.0254f;
         instrumentHeaders[i].offset[2] *= 0.0254f;
       }
       // Same for the content of the measure. The BSF file format seems to save the data in pound and pound-inch
       for (int i = 0 ; i < numberOfActivePlatforms ; ++i)
       {
         scale[i*6] *= 4.4482216152605;
         scale[i*6+1] *= 4.4482216152605;
         scale[i*6+2] *= 4.4482216152605;
         scale[i*6+3] *= 0.1129848290276167;
         scale[i*6+4] *= 0.1129848290276167;
         scale[i*6+5] *= 0.1129848290276167;
       }
       output->SetPointUnit(Point::Marker, "m");
       output->SetPointUnit(Point::Force, "N");
       output->SetPointUnit(Point::Moment, "Nm");
     }
     Acquisition::AnalogIterator it = output->BeginAnalog();
     std::vector<float> corners(12*numberOfActivePlatforms, 0.0f);
     std::vector<float> origin(3*numberOfActivePlatforms, 0.0f);
     std::vector<int16_t> channel(6*numberOfActivePlatforms);
     std::string suffix = ((numberOfActivePlatforms == 1) ? "" : "1");
     float globalOrigin[3] = {0.0f, 0.0f, 0.0f};
     int numToAdaptChannelIndex = 0;
     for (int i = 0 ; i < numberOfActivePlatforms ; ++i)
     {
       (*it)->SetLabel("Fx" + suffix);
       (*it)->SetUnit(output->GetPointUnit(Point::Force));
       (*it)->SetScale(scale[i*6]);
       ++it;
       (*it)->SetLabel("Fy" + suffix);
       (*it)->SetUnit(output->GetPointUnit(Point::Force));
       (*it)->SetScale(scale[i*6+1]);
       ++it;
       (*it)->SetLabel("Fz" + suffix);
       (*it)->SetUnit(output->GetPointUnit(Point::Force));
       (*it)->SetScale(scale[i*6+2]);
       ++it;
       (*it)->SetLabel("Mx" + suffix);
       (*it)->SetUnit(output->GetPointUnit(Point::Moment));
       (*it)->SetScale(scale[i*6+3]);
       ++it;
       (*it)->SetLabel("My" + suffix);
       (*it)->SetUnit(output->GetPointUnit(Point::Moment));
       (*it)->SetScale(scale[i*6+4]);
       ++it;
       (*it)->SetLabel("Mz" + suffix);
       (*it)->SetUnit(output->GetPointUnit(Point::Moment));
       (*it)->SetScale(scale[i*6+5]);
       ++it;
       if (i > 0)
       {
         if ((instrumentHeaders[i].interDistance[0] == 0.0f) && (instrumentHeaders[i].interDistance[1] == 0.0f) && (instrumentHeaders[i].interDistance[2] == 0.0f))
         {
           btkWarningMacro(filename, "The distance with the previous force platform is set to 0. The platform is automatically shifted in the front of the previous. You might have to modify the origin of the force platform #" + ToString(i) + "in the metadata FORCE_PLATFORM:ORIGIN to locate it correctly in the global frame.");
           instrumentHeaders[i].interDistance[1] = static_cast<float>(instrumentHeaders[i].length + instrumentHeaders[i-1].length) / 2.0f;
         }
       }
       globalOrigin[0] += instrumentHeaders[i].interDistance[0];
       globalOrigin[1] += instrumentHeaders[i].interDistance[1];
       globalOrigin[2] += instrumentHeaders[i].interDistance[2];
       this->extractConfiguration(&(instrumentHeaders[i]), globalOrigin, &(channel[i*6]), &(corners[i*12]), &(origin[i*3]));
       for (int j = 0 ; j < 6 ; ++j)
         channel[i*6+j] += numToAdaptChannelIndex;
       numToAdaptChannelIndex += instrumentHeaders[i].numberOfChannels;
       suffix = ToString(i+2);
     }
     // Create the metadata FORCE_PLATFORM
     btk::MetaData::Pointer forcePlatform = btk::MetaData::New("FORCE_PLATFORM");
     output->GetMetaData()->AppendChild(forcePlatform);
     // - FORCE_PLATFORM:USED
     forcePlatform->AppendChild(btk::MetaData::New("USED", static_cast<int16_t>(numberOfActivePlatforms)));
     // - FORCE_PLATFORM:TYPE
     forcePlatform->AppendChild(btk::MetaData::New("TYPE", std::vector<int16_t>(numberOfActivePlatforms,2)));
     // - FORCE_PLATFORM:ZERO
     std::vector<int16_t> zero(2,0); zero[0] = 1;
     forcePlatform->AppendChild(btk::MetaData::New("ZERO", zero));
     // - FORCE_PLATFORM:CORNERS
     std::vector<uint8_t> dims(3); dims[0] = 3; dims[1] = 4; dims[2] = numberOfActivePlatforms;
     forcePlatform->AppendChild(btk::MetaData::New("CORNERS", dims, corners));
     // - FORCE_PLATFORM:ORIGIN
     dims.resize(2); dims[0] = 3; dims[1] = numberOfActivePlatforms;
     forcePlatform->AppendChild(btk::MetaData::New("ORIGIN", dims, origin));
     // - FORCE_PLATFORM:CHANNEL
     dims.resize(2); dims[0] = 6; dims[1] = numberOfActivePlatforms;
     forcePlatform->AppendChild(btk::MetaData::New("CHANNEL", dims, channel));
     // - FORCE_PLATFORM:CAL_MATRIX
     dims.resize(3); dims[0] = 6; dims[1] = 6; dims[2] = 0;
     forcePlatform->AppendChild(btk::MetaData::New("CAL_MATRIX", dims, std::vector<float>()));
     // Add a metadata to notify that the first frame was not set.
     MetaData::Pointer btkPointConfig = MetaDataCreateChild(output->GetMetaData(), "BTK_POINT_CONFIG");
     MetaDataCreateChild(btkPointConfig, "NO_FIRST_FRAME", static_cast<int8_t>(1));
     
     // Data
     // Note: We want the reaction of the measure, so all the data are multiplied by -1.
     for (int i = 0 ; i < output->GetAnalogFrameNumber() ; ++i)
     {
       int inc = 0;
       for (Acquisition::AnalogIterator it = output->BeginAnalog() ; it != output->EndAnalog() ; ++it)
         (*it)->GetValues().coeffRef(i) = -1.0f * static_cast<double>(bifs.ReadI16()) * scale[inc++]; 
     }
     
     // Cleaning
     delete[] scale;
   }
   catch (BinaryFileStreamFailure& )
   {
     std::string excmsg; 
     if (bifs.EndFile())
       excmsg = "Unexpected end of file.";
     else if (!bifs.IsOpen())
       excmsg = "Invalid file path.";
     else if(bifs.Bad())
       excmsg = "Loss of integrity of the file stream.";
     else if(bifs.Fail())
       excmsg = "Internal logic operation error on the stream associated with the file.";
     else
       excmsg = "Unknown error associated with the file stream.";
     
     if (bifs.IsOpen()) bifs.Close();
     throw(BSFFileIOException(excmsg));
   }
   catch (BSFFileIOException& )
   {
     if (bifs.IsOpen()) bifs.Close();
     throw;
   }
   catch (std::exception& e)
   {
     if (bifs.IsOpen()) bifs.Close();
     throw(BSFFileIOException("Unexpected exception occurred: " + std::string(e.what())));
   }
   catch(...)
   {
     if (bifs.IsOpen()) bifs.Close();
     throw(BSFFileIOException("Unknown exception"));
   }
 };